diff --git a/RESEND-sunxi-mmc-increase-status-register-polling-rate-for-data-transfers.patch b/RESEND-sunxi-mmc-increase-status-register-polling-rate-for-data-transfers.patch new file mode 100644 index 0000000..6d16e43 --- /dev/null +++ b/RESEND-sunxi-mmc-increase-status-register-polling-rate-for-data-transfers.patch @@ -0,0 +1,55 @@ +From patchwork Fri Jul 8 10:40:14 2016 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [U-Boot, + RESEND] sunxi: mmc: increase status register polling rate for data + transfers +From: Tobias Doerffel +X-Patchwork-Id: 646568 +X-Patchwork-Delegate: hdegoede@redhat.com +Message-Id: <1467974414-18845-1-git-send-email-tobias.doerffel@ed-chemnitz.de> +To: u-boot@lists.denx.de +Cc: Tobias Doerffel , ijc@hellion.org.uk +Date: Fri, 8 Jul 2016 12:40:14 +0200 + +With a recent bunch of SD3.0 cards in our A20-based board we +experienced data transfer rates of about 250 KiB/s instead of 10 MiB/s +with previous cards from the same vendor (both 4 GB/class 10). By +increasing status register polling rate from 1 kHz to 1 MHz we were +able to reach the original transfer rates again. With the old cards +we now even reach about 16 MiB/s. + +Signed-off-by: Tobias Doerffel +--- + drivers/mmc/sunxi_mmc.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c +index ce2dc4a..36da3b3 100644 +--- a/drivers/mmc/sunxi_mmc.c ++++ b/drivers/mmc/sunxi_mmc.c +@@ -269,18 +269,18 @@ static int mmc_trans_data_by_cpu(struct mmc *mmc, struct mmc_data *data) + unsigned i; + unsigned *buff = (unsigned int *)(reading ? data->dest : data->src); + unsigned byte_cnt = data->blocksize * data->blocks; +- unsigned timeout_msecs = byte_cnt >> 8; +- if (timeout_msecs < 2000) +- timeout_msecs = 2000; ++ unsigned timeout_usecs = (byte_cnt >> 8) * 1000; ++ if (timeout_usecs < 2000000) ++ timeout_usecs = 2000000; + + /* Always read / write data through the CPU */ + setbits_le32(&mmchost->reg->gctrl, SUNXI_MMC_GCTRL_ACCESS_BY_AHB); + + for (i = 0; i < (byte_cnt >> 2); i++) { + while (readl(&mmchost->reg->status) & status_bit) { +- if (!timeout_msecs--) ++ if (!timeout_usecs--) + return -1; +- udelay(1000); ++ udelay(1); + } + + if (reading) diff --git a/net-Add-EMAC-driver-for-H3-A83T-A64-SoCs..patch b/net-Add-EMAC-driver-for-H3-A83T-A64-SoCs..patch new file mode 100644 index 0000000..4f48807 --- /dev/null +++ b/net-Add-EMAC-driver-for-H3-A83T-A64-SoCs..patch @@ -0,0 +1,1076 @@ +From patchwork Wed Jul 6 12:29:44 2016 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [U-Boot,U-BOOT,v2] net:Add EMAC driver for H3/A83T/A64 SoCs. +From: Amit Tomar +X-Patchwork-Id: 645258 +X-Patchwork-Delegate: hdegoede@redhat.com +Message-Id: <1467808184-21998-1-git-send-email-amittomer25@gmail.com> +To: u-boot@lists.denx.de +Cc: Andre Przywara , + LABBE Corentin +Date: Wed, 6 Jul 2016 17:59:44 +0530 + +This patch add EMAC driver support for H3/A83T/A64 SoCs. +Tested on Pine64(A64-External PHY) and Orangepipc(H3-Internal PHY). + +BIG Thanks to Andre for providing some of the DT code. + +Signed-off-by: Amit Singh Tomar +--- +Changes since v1: + * Addressed LABBE's comments. + * Made it compatible with External PHY. +--- + arch/arm/dts/sun50i-a64-pine64-plus.dts | 13 + + arch/arm/dts/sun50i-a64.dtsi | 33 ++ + arch/arm/dts/sun8i-h3-orangepi-2.dts | 13 + + arch/arm/dts/sun8i-h3-orangepi-pc.dts | 12 + + arch/arm/dts/sun8i-h3.dtsi | 25 + + arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 4 +- + arch/arm/include/asm/arch-sunxi/cpu_sun4i.h | 3 +- + configs/orangepi_pc_defconfig | 1 + + configs/pine64_plus_defconfig | 1 + + drivers/net/Kconfig | 9 + + drivers/net/Makefile | 1 + + drivers/net/sun8i_emac.c | 789 +++++++++++++++++++++++++ + 12 files changed, 902 insertions(+), 2 deletions(-) + create mode 100644 drivers/net/sun8i_emac.c + +diff --git a/arch/arm/dts/sun50i-a64-pine64-plus.dts b/arch/arm/dts/sun50i-a64-pine64-plus.dts +index 549dc15..389c609 100644 +--- a/arch/arm/dts/sun50i-a64-pine64-plus.dts ++++ b/arch/arm/dts/sun50i-a64-pine64-plus.dts +@@ -57,3 +57,16 @@ + reg = <0x40000000 0x40000000>; + }; + }; ++ ++&emac { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&rgmii_pins>; ++ phy-mode = "rgmii"; ++ phy = <&phy1>; ++ status = "okay"; ++ ++ phy1: ethernet-phy@1 { ++ reg = <1>; ++ }; ++}; ++ +diff --git a/arch/arm/dts/sun50i-a64.dtsi b/arch/arm/dts/sun50i-a64.dtsi +index 1bd436f..7d0dc76 100644 +--- a/arch/arm/dts/sun50i-a64.dtsi ++++ b/arch/arm/dts/sun50i-a64.dtsi +@@ -506,6 +506,25 @@ + allwinner,drive = ; + allwinner,pull = ; + }; ++ ++ rmii_pins: rmii_pins { ++ allwinner,pins = "PD10", "PD11", "PD13", "PD14", ++ "PD17", "PD18", "PD19", "PD20", ++ "PD22", "PD23"; ++ allwinner,function = "emac"; ++ allwinner,drive = ; ++ allwinner,pull = ; ++ }; ++ ++ rgmii_pins: rgmii_pins { ++ allwinner,pins = "PD8", "PD9", "PD10", "PD11", ++ "PD12", "PD13", "PD15", ++ "PD16", "PD17", "PD18", "PD19", ++ "PD20", "PD21", "PD22", "PD23"; ++ allwinner,function = "emac"; ++ allwinner,drive = ; ++ allwinner,pull = ; ++ }; + }; + + ahb_rst: reset@1c202c0 { +@@ -620,5 +639,19 @@ + #address-cells = <1>; + #size-cells = <0>; + }; ++ ++ emac: ethernet@01c30000 { ++ compatible = "allwinner,sun50i-a64-emac"; ++ reg = <0x01c30000 0x2000>, <0x01c00030 0x4>; ++ reg-names = "emac", "syscon"; ++ interrupts = ; ++ resets = <&ahb_rst 17>; ++ reset-names = "ahb"; ++ clocks = <&bus_gates 17>; ++ clock-names = "ahb"; ++ status = "disabled"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; + }; + }; +diff --git a/arch/arm/dts/sun8i-h3-orangepi-2.dts b/arch/arm/dts/sun8i-h3-orangepi-2.dts +index f93f5d1..d3f8f55 100644 +--- a/arch/arm/dts/sun8i-h3-orangepi-2.dts ++++ b/arch/arm/dts/sun8i-h3-orangepi-2.dts +@@ -184,3 +184,16 @@ + usb1_vbus-supply = <®_usb1_vbus>; + status = "okay"; + }; ++ ++&emac { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&rgmii_pins>; ++ phy-mode = "rgmii"; ++ phy = <&phy1>; ++ status = "okay"; ++ ++ phy1: ethernet-phy@1 { ++ reg = <1>; ++ }; ++}; ++ +diff --git a/arch/arm/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/dts/sun8i-h3-orangepi-pc.dts +index 30ccca0..0a74a91 100644 +--- a/arch/arm/dts/sun8i-h3-orangepi-pc.dts ++++ b/arch/arm/dts/sun8i-h3-orangepi-pc.dts +@@ -173,3 +173,15 @@ + /* USB VBUS is always on */ + status = "okay"; + }; ++ ++&emac { ++ phy = <&phy1>; ++ phy-mode = "mii"; ++ allwinner,use-internal-phy; ++ allwinner,leds-active-low; ++ status = "okay"; ++ ++ phy1: ethernet-phy@1 { ++ reg = <1>; ++ }; ++}; +diff --git a/arch/arm/dts/sun8i-h3.dtsi b/arch/arm/dts/sun8i-h3.dtsi +index c2f63c5..6ca5e34 100644 +--- a/arch/arm/dts/sun8i-h3.dtsi ++++ b/arch/arm/dts/sun8i-h3.dtsi +@@ -501,6 +501,17 @@ + interrupt-controller; + #interrupt-cells = <3>; + ++ rgmii_pins: rgmii_pins { ++ allwinner,pins = "PD0", "PD1", "PD2", "PD3", ++ "PD4", "PD5", "PD7", ++ "PD8", "PD9", "PD10", ++ "PD12", "PD13", "PD15", ++ "PD16", "PD17"; ++ allwinner,function = "emac"; ++ allwinner,drive = ; ++ allwinner,pull = ; ++ }; ++ + uart0_pins_a: uart0@0 { + allwinner,pins = "PA4", "PA5"; + allwinner,function = "uart0"; +@@ -616,6 +627,20 @@ + status = "disabled"; + }; + ++ emac: ethernet@01c30000 { ++ compatible = "allwinner,sun8i-h3-emac"; ++ reg = <0x01c30000 0x2000>, <0x01c00030 0x4>; ++ reg-names = "emac", "syscon"; ++ interrupts = ; ++ resets = <&ahb_rst 17>, <&ahb_rst 66>; ++ reset-names = "ahb", "ephy"; ++ clocks = <&bus_gates 17>, <&bus_gates 128>; ++ clock-names = "ahb", "ephy"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ + gic: interrupt-controller@01c81000 { + compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic"; + reg = <0x01c81000 0x1000>, +diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h +index c2e72f5..d4dff1e 100644 +--- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h ++++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h +@@ -40,7 +40,8 @@ struct sunxi_ccm_reg { + u32 ahb_gate1; /* 0x64 ahb module clock gating 1 */ + u32 apb1_gate; /* 0x68 apb1 module clock gating */ + u32 apb2_gate; /* 0x6c apb2 module clock gating */ +- u32 reserved9[4]; ++ u32 bus_gate4; /* 0x70 gate 4 module clock gating */ ++ u8 res3[0xc]; + u32 nand0_clk_cfg; /* 0x80 nand0 clock control */ + u32 nand1_clk_cfg; /* 0x84 nand1 clock control */ + u32 sd0_clk_cfg; /* 0x88 sd0 clock control */ +@@ -387,6 +388,7 @@ struct sunxi_ccm_reg { + #define AHB_RESET_OFFSET_LCD0 4 + + /* ahb_reset2 offsets */ ++#define AHB_RESET_OFFSET_EPHY 2 + #define AHB_RESET_OFFSET_LVDS 0 + + /* apb2 reset */ +diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h +index c5e9d88..cd009d7 100644 +--- a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h ++++ b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h +@@ -87,7 +87,8 @@ + #define SUNXI_KEYPAD_BASE 0x01c23000 + #define SUNXI_TZPC_BASE 0x01c23400 + +-#if defined(CONFIG_MACH_SUN8I_A83T) || defined(CONFIG_MACH_SUN8I_H3) ++#if defined(CONFIG_MACH_SUN8I_A83T) || defined(CONFIG_MACH_SUN8I_H3) || \ ++defined(CONFIG_MACH_SUN50I) + /* SID address space starts at 0x01c1400, but e-fuse is at offset 0x200 */ + #define SUNXI_SID_BASE 0x01c14200 + #else +diff --git a/configs/orangepi_pc_defconfig b/configs/orangepi_pc_defconfig +index 7eaa795..294f7ab 100644 +--- a/configs/orangepi_pc_defconfig ++++ b/configs/orangepi_pc_defconfig +@@ -13,3 +13,4 @@ CONFIG_SPL=y + # CONFIG_CMD_FPGA is not set + CONFIG_SY8106A_POWER=y + CONFIG_USB_EHCI_HCD=y ++CONFIG_SUN8I_EMAC=y +diff --git a/configs/pine64_plus_defconfig b/configs/pine64_plus_defconfig +index 0bf79bf..5c97de1 100644 +--- a/configs/pine64_plus_defconfig ++++ b/configs/pine64_plus_defconfig +@@ -10,3 +10,4 @@ CONFIG_DEFAULT_DEVICE_TREE="sun50i-a64-pine64-plus" + # CONFIG_CMD_FLASH is not set + # CONFIG_CMD_FPGA is not set + CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK=y ++CONFIG_SUN8I_EMAC=y +diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig +index c1cb689..88d8e83 100644 +--- a/drivers/net/Kconfig ++++ b/drivers/net/Kconfig +@@ -152,6 +152,15 @@ config RTL8169 + This driver supports Realtek 8169 series gigabit ethernet family of + PCI/PCIe chipsets/adapters. + ++config SUN8I_EMAC ++ bool "Allwinner Sun8i Ethernet MAC support" ++ depends on DM_ETH ++ select PHYLIB ++ help ++ This driver supports the Allwinner based SUN8I/SUN50I Ethernet MAC. ++ It can be found in H3/A64/A83T based SoCs and compatible with both ++ External and Internal PHY's. ++ + config XILINX_AXIEMAC + depends on DM_ETH && (MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP) + select PHYLIB +diff --git a/drivers/net/Makefile b/drivers/net/Makefile +index 5702592..a448526 100644 +--- a/drivers/net/Makefile ++++ b/drivers/net/Makefile +@@ -24,6 +24,7 @@ obj-$(CONFIG_E1000) += e1000.o + obj-$(CONFIG_E1000_SPI) += e1000_spi.o + obj-$(CONFIG_EEPRO100) += eepro100.o + obj-$(CONFIG_SUNXI_EMAC) += sunxi_emac.o ++obj-$(CONFIG_SUN8I_EMAC) += sun8i_emac.o + obj-$(CONFIG_ENC28J60) += enc28j60.o + obj-$(CONFIG_EP93XX) += ep93xx_eth.o + obj-$(CONFIG_ETHOC) += ethoc.o +diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c +new file mode 100644 +index 0000000..4bed50d +--- /dev/null ++++ b/drivers/net/sun8i_emac.c +@@ -0,0 +1,789 @@ ++/* ++ * (C) Copyright 2016 ++ * Author: Amit Singh Tomar, amittomer25@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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define SCTL_EMAC_TX_CLK_SRC_MII BIT(0) ++#define SCTL_EMAC_EPIT_MII BIT(2) ++#define SCTL_EMAC_CLK_SEL BIT(18) /* 25 Mhz */ ++ ++#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 CONFIG_TX_DESCR_NUM 32 ++#define CONFIG_RX_DESCR_NUM 32 ++#define CONFIG_ETH_BUFSIZE 2024 ++ ++#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 ++ ++DECLARE_GLOBAL_DATA_PTR; ++ ++enum emac_variant { ++ A83T_EMAC = 1, ++ H3_EMAC, ++ A64_EMAC, ++}; ++ ++struct emac_dma_desc { ++ u32 status; ++ u32 st; ++ u32 buf_addr; ++ u32 next; ++} __aligned(ARCH_DMA_MINALIGN); ++ ++struct emac_eth_dev { ++ struct emac_dma_desc rx_chain[CONFIG_TX_DESCR_NUM]; ++ struct emac_dma_desc tx_chain[CONFIG_RX_DESCR_NUM]; ++ char rxbuffer[RX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN); ++ char txbuffer[TX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN); ++ ++ u32 interface; ++ u32 phyaddr; ++ u32 link; ++ u32 speed; ++ u32 duplex; ++ u32 phy_configured; ++ u32 tx_currdescnum; ++ u32 rx_currdescnum; ++ u32 addr; ++ u32 tx_slot; ++ bool use_internal_phy; ++ ++ enum emac_variant variant; ++ void *mac_reg; ++ phys_addr_t sysctl_reg; ++ struct phy_device *phydev; ++ struct mii_dev *bus; ++}; ++ ++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; ++ ++ 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; ++ ++ writel(miiaddr, priv->mac_reg + EMAC_MII_CMD); ++ writel(val, priv->mac_reg + EMAC_MII_DATA); ++ ++ 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; ++} ++ ++static int _sun8i_write_hwaddr(struct emac_eth_dev *priv, u8 *mac_id) ++{ ++ u32 macid_lo, macid_hi; ++ ++ macid_lo = mac_id[0] + (mac_id[1] << 8) + (mac_id[2] << 16) + ++ (mac_id[3] << 24); ++ macid_hi = mac_id[4] + (mac_id[5] << 8); ++ ++ writel(macid_hi, priv->mac_reg + EMAC_ADDR0_HIGH); ++ writel(macid_lo, priv->mac_reg + EMAC_ADDR0_LOW); ++ ++ return 0; ++} ++ ++static void sun8i_adjust_link(struct emac_eth_dev *priv, ++ struct phy_device *phydev) ++{ ++ u32 v; ++ ++ v = readl(priv->mac_reg + EMAC_CTL0); ++ ++ if (phydev->duplex) ++ v |= BIT(0); ++ else ++ v &= ~BIT(0); ++ ++ v &= ~0x0C; ++ ++ switch (phydev->speed) { ++ case 1000: ++ break; ++ case 100: ++ v |= BIT(2); ++ v |= BIT(3); ++ break; ++ case 10: ++ v |= BIT(3); ++ break; ++ } ++ writel(v, priv->mac_reg + EMAC_CTL0); ++} ++ ++static int sun8i_emac_set_syscon_ephy(struct emac_eth_dev *priv, u32 *reg) ++{ ++ if (priv->use_internal_phy) { ++ /* H3 based SoC's that has an Internal 100MBit PHY ++ * needs to be configured and powered up before use ++ */ ++ *reg &= ~H3_EPHY_DEFAULT_MASK; ++ *reg |= H3_EPHY_DEFAULT_VALUE; ++ *reg |= priv->phyaddr << H3_EPHY_ADDR_SHIFT; ++ *reg &= ~H3_EPHY_SHUTDOWN; ++ *reg |= H3_EPHY_SELECT; ++ } else ++ /* This is to select External Gigabit PHY on ++ * the boards with H3 SoC. ++ */ ++ *reg &= ~H3_EPHY_SELECT; ++ ++ return 0; ++} ++ ++static int sun8i_emac_set_syscon(struct emac_eth_dev *priv) ++{ ++ int ret; ++ u32 reg; ++ ++ reg = readl(priv->sysctl_reg); ++ ++ if (priv->variant == H3_EMAC) { ++ ret = sun8i_emac_set_syscon_ephy(priv, ®); ++ if (ret) ++ return ret; ++ } ++ ++ reg &= ~(SC_ETCS_MASK | SC_EPIT); ++ if (priv->variant == H3_EMAC || priv->variant == A64_EMAC) ++ reg &= ~SC_RMII_EN; ++ ++ switch (priv->interface) { ++ case PHY_INTERFACE_MODE_MII: ++ /* default */ ++ break; ++ case PHY_INTERFACE_MODE_RGMII: ++ reg |= SC_EPIT | SC_ETCS_INT_GMII; ++ break; ++ case PHY_INTERFACE_MODE_RMII: ++ if (priv->variant == H3_EMAC || ++ priv->variant == A64_EMAC) { ++ reg |= SC_RMII_EN | SC_ETCS_EXT_GMII; ++ break; ++ } ++ /* RMII not supported on A83T */ ++ default: ++ debug("%s: Invalid PHY interface\n", __func__); ++ return -EINVAL; ++ } ++ ++ writel(reg, priv->sysctl_reg); ++ ++ return 0; ++} ++ ++static int sun8i_phy_init(struct emac_eth_dev *priv, void *dev) ++{ ++ struct phy_device *phydev; ++ ++ phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface); ++ if (!phydev) ++ return -ENODEV; ++ ++ phy_connect_dev(phydev, dev); ++ ++ priv->phydev = phydev; ++ phy_config(priv->phydev); ++ ++ return 0; ++} ++ ++static void rx_descs_init(struct emac_eth_dev *priv) ++{ ++ struct emac_dma_desc *desc_table_p = &priv->rx_chain[0]; ++ char *rxbuffs = &priv->rxbuffer[0]; ++ struct emac_dma_desc *desc_p; ++ u32 idx; ++ ++ /* flush Rx buffers */ ++ flush_dcache_range((uintptr_t)rxbuffs, (ulong)rxbuffs + ++ RX_TOTAL_BUFSIZE); ++ ++ for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) { ++ desc_p = &desc_table_p[idx]; ++ desc_p->buf_addr = (uintptr_t)&rxbuffs[idx * CONFIG_ETH_BUFSIZE] ++ ; ++ desc_p->next = (uintptr_t)&desc_table_p[idx + 1]; ++ desc_p->st |= CONFIG_ETH_BUFSIZE; ++ desc_p->status = BIT(31); ++ } ++ ++ /* Correcting the last pointer of the chain */ ++ desc_p->next = (uintptr_t)&desc_table_p[0]; ++ ++ flush_dcache_range((uintptr_t)priv->rx_chain, ++ (uintptr_t)priv->rx_chain + ++ sizeof(priv->rx_chain)); ++ ++ writel((uintptr_t)&desc_table_p[0], (priv->mac_reg + EMAC_RX_DMA_DESC)); ++ priv->rx_currdescnum = 0; ++} ++ ++static void tx_descs_init(struct emac_eth_dev *priv) ++{ ++ struct emac_dma_desc *desc_table_p = &priv->tx_chain[0]; ++ char *txbuffs = &priv->txbuffer[0]; ++ struct emac_dma_desc *desc_p; ++ u32 idx; ++ ++ for (idx = 0; idx < CONFIG_TX_DESCR_NUM; idx++) { ++ desc_p = &desc_table_p[idx]; ++ desc_p->buf_addr = (uintptr_t)&txbuffs[idx * CONFIG_ETH_BUFSIZE] ++ ; ++ desc_p->next = (uintptr_t)&desc_table_p[idx + 1]; ++ desc_p->status = (1 << 31); ++ desc_p->st = 0; ++ } ++ ++ /* Correcting the last pointer of the chain */ ++ desc_p->next = (uintptr_t)&desc_table_p[0]; ++ ++ /* Flush all Tx buffer descriptors */ ++ flush_dcache_range((uintptr_t)priv->tx_chain, ++ (uintptr_t)priv->tx_chain + ++ sizeof(priv->tx_chain)); ++ ++ writel((uintptr_t)&desc_table_p[0], priv->mac_reg + EMAC_TX_DMA_DESC); ++ priv->tx_currdescnum = 0; ++} ++ ++static int _sun8i_emac_eth_init(struct emac_eth_dev *priv, u8 *enetaddr) ++{ ++ u32 reg, v; ++ int timeout = 100; ++ ++ reg = readl((priv->mac_reg + EMAC_CTL1)); ++ ++ if (!(reg & 0x1)) { ++ /* Soft reset MAC */ ++ setbits_le32((priv->mac_reg + EMAC_CTL1), 0x1); ++ do { ++ reg = readl(priv->mac_reg + EMAC_CTL1); ++ } while ((reg & 0x01) != 0 && (--timeout)); ++ if (!timeout) { ++ printf("%s: Timeout\n", __func__); ++ return -1; ++ } ++ } ++ ++ /* Rewrite mac address after reset */ ++ _sun8i_write_hwaddr(priv, enetaddr); ++ ++ v = readl(priv->mac_reg + EMAC_TX_CTL1); ++ /* TX_MD Transmission starts after a full frame located in TX DMA FIFO*/ ++ v |= BIT(1); ++ writel(v, priv->mac_reg + EMAC_TX_CTL1); ++ ++ v = readl(priv->mac_reg + EMAC_RX_CTL1); ++ /* RX_MD RX DMA reads data from RX DMA FIFO to host memory after a ++ * complete frame has been written to RX DMA FIFO ++ */ ++ v |= BIT(1); ++ writel(v, priv->mac_reg + EMAC_RX_CTL1); ++ ++ /* DMA */ ++ writel(8 << 24, priv->mac_reg + EMAC_CTL1); ++ ++ /* Initialize rx/tx descriptors */ ++ rx_descs_init(priv); ++ tx_descs_init(priv); ++ ++ /* PHY Start Up */ ++ genphy_parse_link(priv->phydev); ++ ++ sun8i_adjust_link(priv, priv->phydev); ++ ++ /* Start RX DMA */ ++ v = readl(priv->mac_reg + EMAC_RX_CTL1); ++ v |= BIT(30); ++ writel(v, priv->mac_reg + EMAC_RX_CTL1); ++ /* Start TX DMA */ ++ v = readl(priv->mac_reg + EMAC_TX_CTL1); ++ v |= BIT(30); ++ writel(v, priv->mac_reg + EMAC_TX_CTL1); ++ ++ /* Enable RX/TX */ ++ setbits_le32(priv->mac_reg + EMAC_RX_CTL0, BIT(31)); ++ setbits_le32(priv->mac_reg + EMAC_TX_CTL0, BIT(31)); ++ ++ return 0; ++} ++ ++static int parse_phy_pins(struct udevice *dev) ++{ ++ int offset; ++ const char *pin_name; ++ int drive, pull, i; ++ ++ offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset, ++ "pinctrl-0"); ++ if (offset < 0) { ++ printf("WARNING: emac: cannot find pinctrl-0 node\n"); ++ return offset; ++ } ++ ++ drive = fdt_getprop_u32_default_node(gd->fdt_blob, offset, 0, ++ "allwinner,drive", 4); ++ pull = fdt_getprop_u32_default_node(gd->fdt_blob, offset, 0, ++ "allwinner,pull", 0); ++ for (i = 0; ; i++) { ++ int pin; ++ ++ if (fdt_get_string_index(gd->fdt_blob, offset, ++ "allwinner,pins", i, &pin_name)) ++ break; ++ if (pin_name[0] != 'P') ++ continue; ++ pin = (pin_name[1] - 'A') << 5; ++ if (pin >= 26 << 5) ++ continue; ++ pin += simple_strtol(&pin_name[2], NULL, 10); ++ ++ sunxi_gpio_set_cfgpin(pin, SUN8I_GPD8_GMAC); ++ sunxi_gpio_set_drv(pin, drive); ++ sunxi_gpio_set_pull(pin, pull); ++ } ++ ++ if (!i) { ++ printf("WARNING: emac: cannot find allwinner,pins property\n"); ++ return -2; ++ } ++ ++ return 0; ++} ++ ++static int _sun8i_eth_recv(struct emac_eth_dev *priv, uchar **packetp) ++{ ++ u32 status, desc_num = priv->rx_currdescnum; ++ struct emac_dma_desc *desc_p = &priv->rx_chain[desc_num]; ++ int length = -EAGAIN; ++ int good_packet = 1; ++ uintptr_t desc_start = (uintptr_t)desc_p; ++ uintptr_t desc_end = desc_start + ++ roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN); ++ ++ ulong data_start = (uintptr_t)desc_p->buf_addr; ++ ulong data_end; ++ ++ /* Invalidate entire buffer descriptor */ ++ invalidate_dcache_range(desc_start, desc_end); ++ ++ status = desc_p->status; ++ ++ /* Check for DMA own bit */ ++ if (!(status & BIT(31))) { ++ length = (desc_p->status >> 16) & 0x3FFF; ++ ++ if (length < 0x40) { ++ good_packet = 0; ++ debug("RX: Bad Packet (runt)\n"); ++ } ++ ++ data_end = data_start + length; ++ /* Invalidate received data */ ++ invalidate_dcache_range(rounddown(data_start, ++ ARCH_DMA_MINALIGN), ++ roundup(data_end, ++ ARCH_DMA_MINALIGN)); ++ if (good_packet) { ++ if (length > CONFIG_ETH_BUFSIZE) { ++ printf("Received packet is too big (len=%d)\n", ++ length); ++ return -EMSGSIZE; ++ } ++ *packetp = (uchar *)(ulong)desc_p->buf_addr; ++ return length; ++ } ++ } ++ ++ return length; ++} ++ ++static int _sun8i_emac_eth_send(struct emac_eth_dev *priv, void *packet, ++ int len) ++{ ++ u32 v, desc_num = priv->tx_currdescnum; ++ struct emac_dma_desc *desc_p = &priv->tx_chain[desc_num]; ++ uintptr_t desc_start = (uintptr_t)desc_p; ++ uintptr_t desc_end = desc_start + ++ roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN); ++ ++ uintptr_t data_start = (uintptr_t)desc_p->buf_addr; ++ uintptr_t data_end = data_start + ++ roundup(len, ARCH_DMA_MINALIGN); ++ ++ /* Invalidate entire buffer descriptor */ ++ invalidate_dcache_range(desc_start, desc_end); ++ ++ desc_p->st = len; ++ /* Mandatory undocumented bit */ ++ desc_p->st |= BIT(24); ++ ++ memcpy((void *)data_start, packet, len); ++ ++ /* Flush data to be sent */ ++ flush_dcache_range(data_start, data_end); ++ ++ /* frame end */ ++ desc_p->st |= BIT(30); ++ desc_p->st |= BIT(31); ++ ++ /*frame begin */ ++ desc_p->st |= BIT(29); ++ desc_p->status = BIT(31); ++ ++ /*Descriptors st and status field has changed, so FLUSH it */ ++ flush_dcache_range(desc_start, desc_end); ++ ++ /* Move to next Descriptor and wrap around */ ++ if (++desc_num >= CONFIG_TX_DESCR_NUM) ++ desc_num = 0; ++ priv->tx_currdescnum = desc_num; ++ ++ /* Start the DMA */ ++ v = readl(priv->mac_reg + EMAC_TX_CTL1); ++ v |= BIT(31);/* mandatory */ ++ v |= BIT(30);/* mandatory */ ++ writel(v, priv->mac_reg + EMAC_TX_CTL1); ++ ++ return 0; ++} ++ ++static int sun8i_eth_write_hwaddr(struct udevice *dev) ++{ ++ struct eth_pdata *pdata = dev_get_platdata(dev); ++ struct emac_eth_dev *priv = dev_get_priv(dev); ++ ++ return _sun8i_write_hwaddr(priv, pdata->enetaddr); ++} ++ ++static void sun8i_emac_board_setup(struct emac_eth_dev *priv) ++{ ++ struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; ++ ++ if (priv->use_internal_phy) { ++ /* Set clock gating for ephy */ ++ setbits_le32(&ccm->bus_gate4, BIT(AHB_GATE_OFFSET_EPHY)); ++ ++ /* Set Tx clock source as MII with rate 25 MZ */ ++ setbits_le32(priv->sysctl_reg, SCTL_EMAC_TX_CLK_SRC_MII | ++ SCTL_EMAC_EPIT_MII | SCTL_EMAC_CLK_SEL); ++ /* Deassert EPHY */ ++ setbits_le32(&ccm->ahb_reset2_cfg, BIT(AHB_RESET_OFFSET_EPHY)); ++ } ++ ++ /* Set clock gating for emac */ ++ setbits_le32(&ccm->ahb_gate0, BIT(AHB_GATE_OFFSET_GMAC)); ++ ++ /* Set EMAC clock */ ++ setbits_le32(&ccm->axi_gate, (BIT(1) | BIT(0))); ++ ++ /* De-assert EMAC */ ++ setbits_le32(&ccm->ahb_reset0_cfg, BIT(AHB_RESET_OFFSET_GMAC)); ++} ++ ++static int sun8i_mdio_init(const char *name, struct emac_eth_dev *priv) ++{ ++ struct mii_dev *bus = mdio_alloc(); ++ ++ if (!bus) { ++ debug("Failed to allocate MDIO bus\n"); ++ return -ENOMEM; ++ } ++ ++ bus->read = sun8i_mdio_read; ++ bus->write = sun8i_mdio_write; ++ snprintf(bus->name, sizeof(bus->name), name); ++ bus->priv = (void *)priv; ++ ++ return mdio_register(bus); ++} ++ ++static int sun8i_emac_eth_start(struct udevice *dev) ++{ ++ struct eth_pdata *pdata = dev_get_platdata(dev); ++ ++ return _sun8i_emac_eth_init(dev->priv, pdata->enetaddr); ++} ++ ++static int sun8i_emac_eth_send(struct udevice *dev, void *packet, int length) ++{ ++ struct emac_eth_dev *priv = dev_get_priv(dev); ++ ++ return _sun8i_emac_eth_send(priv, packet, length); ++} ++ ++static int sun8i_emac_eth_recv(struct udevice *dev, int flags, uchar **packetp) ++{ ++ struct emac_eth_dev *priv = dev_get_priv(dev); ++ ++ return _sun8i_eth_recv(priv, packetp); ++} ++ ++static int _sun8i_free_pkt(struct emac_eth_dev *priv) ++{ ++ u32 desc_num = priv->rx_currdescnum; ++ struct emac_dma_desc *desc_p = &priv->rx_chain[desc_num]; ++ uintptr_t desc_start = (uintptr_t)desc_p; ++ uintptr_t desc_end = desc_start + ++ roundup(sizeof(u32), ARCH_DMA_MINALIGN); ++ ++ /* Make the current descriptor valid again */ ++ desc_p->status |= BIT(31); ++ ++ /* Flush Status field of descriptor */ ++ flush_dcache_range(desc_start, desc_end); ++ ++ /* Move to next desc and wrap-around condition. */ ++ if (++desc_num >= CONFIG_RX_DESCR_NUM) ++ desc_num = 0; ++ priv->rx_currdescnum = desc_num; ++ ++ return 0; ++} ++ ++static int sun8i_eth_free_pkt(struct udevice *dev, uchar *packet, ++ int length) ++{ ++ struct emac_eth_dev *priv = dev_get_priv(dev); ++ ++ return _sun8i_free_pkt(priv); ++} ++ ++static void sun8i_emac_eth_stop(struct udevice *dev) ++{ ++ struct emac_eth_dev *priv = dev_get_priv(dev); ++ ++ /* Stop Rx/Tx transmitter */ ++ clrbits_le32(priv->mac_reg + EMAC_RX_CTL0, BIT(31)); ++ clrbits_le32(priv->mac_reg + EMAC_TX_CTL0, BIT(31)); ++ ++ /* Stop TX DMA */ ++ clrbits_le32(priv->mac_reg + EMAC_TX_CTL1, BIT(30)); ++ ++ phy_shutdown(priv->phydev); ++} ++ ++static int sun8i_emac_eth_probe(struct udevice *dev) ++{ ++ struct eth_pdata *pdata = dev_get_platdata(dev); ++ struct emac_eth_dev *priv = dev_get_priv(dev); ++ ++ priv->mac_reg = (void *)pdata->iobase; ++ ++ sun8i_emac_board_setup(priv); ++ ++ sun8i_mdio_init(dev->name, priv); ++ priv->bus = miiphy_get_dev_by_name(dev->name); ++ ++ sun8i_emac_set_syscon(priv); ++ ++ return sun8i_phy_init(priv, dev); ++} ++ ++static const struct eth_ops sun8i_emac_eth_ops = { ++ .start = sun8i_emac_eth_start, ++ .write_hwaddr = sun8i_eth_write_hwaddr, ++ .send = sun8i_emac_eth_send, ++ .recv = sun8i_emac_eth_recv, ++ .free_pkt = sun8i_eth_free_pkt, ++ .stop = sun8i_emac_eth_stop, ++}; ++ ++static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev) ++{ ++ struct eth_pdata *pdata = dev_get_platdata(dev); ++ struct emac_eth_dev *priv = dev_get_priv(dev); ++ const char *phy_mode; ++ int offset = 0; ++ ++ pdata->iobase = dev_get_addr_name(dev, "emac"); ++ priv->sysctl_reg = dev_get_addr_name(dev, "syscon"); ++ ++ pdata->phy_interface = -1; ++ priv->phyaddr = -1; ++ priv->use_internal_phy = false; ++ ++ offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset, ++ "phy"); ++ if (offset > 0) ++ priv->phyaddr = fdtdec_get_int(gd->fdt_blob, offset, "reg", ++ -1); ++ ++ phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy-mode", NULL); ++ ++ if (phy_mode) ++ pdata->phy_interface = phy_get_interface_by_name(phy_mode); ++ printf("phy interface%d\n", pdata->phy_interface); ++ ++ if (pdata->phy_interface == -1) { ++ debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode); ++ return -EINVAL; ++ } ++ ++ priv->variant = dev_get_driver_data(dev); ++ ++ if (!priv->variant) { ++ printf("%s: Missing variant '%s'\n", __func__, ++ (char *)priv->variant); ++ return -EINVAL; ++ } ++ ++ if (priv->variant == H3_EMAC) { ++ if (fdt_getprop(gd->fdt_blob, dev->of_offset, ++ "allwinner,use-internal-phy", NULL)) ++ priv->use_internal_phy = true; ++ } ++ ++ priv->interface = pdata->phy_interface; ++ ++ if (!priv->use_internal_phy) ++ parse_phy_pins(dev); ++ ++ return 0; ++} ++ ++static const struct udevice_id sun8i_emac_eth_ids[] = { ++ {.compatible = "allwinner,sun8i-h3-emac", .data = (uintptr_t)H3_EMAC }, ++ {.compatible = "allwinner,sun50i-a64-emac", ++ .data = (uintptr_t)A64_EMAC }, ++ {.compatible = "allwinner,sun8i-a83t-emac", ++ .data = (uintptr_t)A83T_EMAC }, ++ { } ++}; ++ ++U_BOOT_DRIVER(eth_sun8i_emac) = { ++ .name = "eth_sun8i_emac", ++ .id = UCLASS_ETH, ++ .of_match = sun8i_emac_eth_ids, ++ .ofdata_to_platdata = sun8i_emac_eth_ofdata_to_platdata, ++ .probe = sun8i_emac_eth_probe, ++ .ops = &sun8i_emac_eth_ops, ++ .priv_auto_alloc_size = sizeof(struct emac_eth_dev), ++ .platdata_auto_alloc_size = sizeof(struct eth_pdata), ++ .flags = DM_FLAG_ALLOC_PRIV_DMA, ++}; diff --git a/sources b/sources index 5e44eea..31ddb09 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -78f339300a811e7a70dec42520d14110 u-boot-2016.07-rc3.tar.bz2 +425a3fa610a7d972e5092a0e92276c70 u-boot-2016.07.tar.bz2 diff --git a/uboot-tools.spec b/uboot-tools.spec index 7892046..cbec041 100644 --- a/uboot-tools.spec +++ b/uboot-tools.spec @@ -1,8 +1,8 @@ -%global candidate rc3 +#global candidate rc3 Name: uboot-tools Version: 2016.07 -Release: 0.4%{?candidate:.%{candidate}}%{?dist} +Release: 1%{?candidate:.%{candidate}}%{?dist} Summary: U-Boot utilities Group: Development/Tools @@ -16,6 +16,8 @@ Patch1: copy-gcc5-over-to-compiler-gcc6.h-as-a-beginning-of-.patch Patch2: add-BOOTENV_INIT_COMMAND-for-commands-that-may-be-ne.patch Patch3: port-utilite-to-distro-generic-boot-commands.patch Patch4: mvebu-enable-generic-distro-boot-config.patch +Patch5: RESEND-sunxi-mmc-increase-status-register-polling-rate-for-data-transfers.patch +Patch6: net-Add-EMAC-driver-for-H3-A83T-A64-SoCs..patch BuildRequires: bc BuildRequires: dtc @@ -192,6 +194,9 @@ install -p -m 0644 tools/env/fw_env.config $RPM_BUILD_ROOT%{_sysconfdir} %endif %changelog +* Tue Jul 12 2016 Peter Robinson 2016.07-1 +- Update to 2016.07 GA + * Thu Jul 7 2016 Peter Robinson 2016.07-0.4rc3 - Minor updates and cleanups