[U-Boot] [PATCH v2 0/15] Xilinx Zynq patches

Patchset contains several patches which improve Xilinx Zynq arm port. Patchset contain: - core changes - gem updates - mmc support - i2c support - pl support
I am sending them in one package because driver depends on each other in zynq shared files.
Thanks for your comments, Michal
P.S.: The first version sent by patman that's why sorry for any mistake.
Changes in v2: - New patch in this series to reflect Tom's comments - Remove XPSS_ prefix and replace it with ZYNQ - Remove CONFIG_ prefix from non configurable macros (scutimer) - Remove CONFIG_ prefix from non configurable macro (gem) - Remove CONFIG_ prefix from non configurable macros (emio) - Remove CONFIG_ prefix from non configurable macros (sdhci) - Remove CONFIG_ prefix from non configurable macros (i2c) - Fix checkpatch warnings (i2c) - Fix #define<space>Macro name (i2c) - Fix multiline comments (i2c) - Remove trailing 1 for configurations (i2c) - Fix bugs reported by Tom Rini - Fix checkpatch warnings (fpga) - Fix comments (fpga) - Do not use CamelCase for XilinxZynq (fpga)
David Andrey (3): arm: zynq: U-Boot udelay < 1000 FIX net: gem: Pass phy address to init net: gem: Preserve clk on emio interface
Michal Simek (12): arm: zynq: Rename XPSS_ prefix to ZYNQ_ for hardcoded SoC addresses zynq: Move scutimer baseaddr to hardware.h net: phy: Define Marvell 88e1518 phy net: gem: Remove WRAP bit from TX buffer description net: gem: Simplify return path in zynq_gem_recv net: gem: Do not initialize BDs again net: gem: Fix gem driver on 1Gbps LAN zynq: Move macros to hardware.h net: gem: Add support for phy autodetection mmc: Add support for Xilinx Zynq sdhci controller i2c: zynq: Add support for Xilinx Zynq fpga: Add support for loading bitstream for Xilinx Zynq
arch/arm/cpu/armv7/zynq/slcr.c | 61 ++++++ arch/arm/cpu/armv7/zynq/timer.c | 49 ++++- arch/arm/include/asm/arch-zynq/hardware.h | 36 +++- arch/arm/include/asm/arch-zynq/sys_proto.h | 7 + board/xilinx/zynq/board.c | 66 ++++++- drivers/fpga/Makefile | 1 + drivers/fpga/xilinx.c | 37 ++++ drivers/fpga/zynqpl.c | 231 ++++++++++++++++++++++ drivers/i2c/Makefile | 1 + drivers/i2c/zynq_i2c.c | 306 +++++++++++++++++++++++++++++ drivers/mmc/Makefile | 1 + drivers/mmc/zynq_sdhci.c | 40 ++++ drivers/net/phy/marvell.c | 11 ++ drivers/net/zynq_gem.c | 199 +++++++++++++------ include/configs/zynq.h | 39 +++- include/netdev.h | 2 +- include/xilinx.h | 4 + include/zynqpl.h | 59 ++++++ 18 files changed, 1065 insertions(+), 85 deletions(-) create mode 100644 drivers/fpga/zynqpl.c create mode 100644 drivers/i2c/zynq_i2c.c create mode 100644 drivers/mmc/zynq_sdhci.c create mode 100644 include/zynqpl.h
-- 1.8.2.1

From: David Andrey david.andrey@netmodule.com
Rework the __udelay function of U-Boot Zynq Arch to handle delay < 1000 usec
Signed-off-by: David Andrey david.andrey@netmodule.com Signed-off-by: Michal Simek michal.simek@xilinx.com --- Changes in v2: None
arch/arm/cpu/armv7/zynq/timer.c | 46 +++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 9 deletions(-)
diff --git a/arch/arm/cpu/armv7/zynq/timer.c b/arch/arm/cpu/armv7/zynq/timer.c index 45b405a..5d8bb24 100644 --- a/arch/arm/cpu/armv7/zynq/timer.c +++ b/arch/arm/cpu/armv7/zynq/timer.c @@ -114,15 +114,43 @@ ulong get_timer_masked(void)
void __udelay(unsigned long usec) { - unsigned long long tmp; - ulong tmo; - - tmo = usec / (1000000 / CONFIG_SYS_HZ); - tmp = get_ticks() + tmo; /* Get current timestamp */ - - while (get_ticks() < tmp) { /* Loop till event */ - /* NOP */; - } + u32 countticks; + u32 timeend; + u32 timediff; + u32 timenow; + + if (usec == 0) + return; + + countticks = (u32) (((unsigned long long) TIMER_TICK_HZ * usec) / + 1000000); + + /* decrementing timer */ + timeend = readl(&timer_base->counter) - countticks; + +#if TIMER_LOAD_VAL != 0xFFFFFFFF + /* do not manage multiple overflow */ + if (countticks >= TIMER_LOAD_VAL) + countticks = TIMER_LOAD_VAL - 1; +#endif + + do { + timenow = readl(&timer_base->counter); + + if (timenow >= timeend) { + /* normal case */ + timediff = timenow - timeend; + } else { + if ((TIMER_LOAD_VAL - timeend + timenow) <= + countticks) { + /* overflow */ + timediff = TIMER_LOAD_VAL - timeend + timenow; + } else { + /* missed the exact match */ + break; + } + } + } while (timediff > 0); }
/* Timer without interrupts */ -- 1.8.2.1

XPSS prefix was used in past and it is obsolete for quite some time. Let's use correct SoC name which is Zynq.
Signed-off-by: Michal Simek michal.simek@xilinx.com --- Changes in v2: - New patch in this series to reflect Tom's comments - Remove XPSS_ prefix and replace it with ZYNQ
arch/arm/include/asm/arch-zynq/hardware.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/arch/arm/include/asm/arch-zynq/hardware.h b/arch/arm/include/asm/arch-zynq/hardware.h index d0c69da..a99edbe 100644 --- a/arch/arm/include/asm/arch-zynq/hardware.h +++ b/arch/arm/include/asm/arch-zynq/hardware.h @@ -23,9 +23,9 @@ #ifndef _ASM_ARCH_HARDWARE_H #define _ASM_ARCH_HARDWARE_H
-#define XPSS_SYS_CTRL_BASEADDR 0xF8000000 -#define XPSS_DEV_CFG_APB_BASEADDR 0xF8007000 -#define XPSS_SCU_BASEADDR 0xF8F00000 +#define ZYNQ_SYS_CTRL_BASEADDR 0xF8000000 +#define ZYNQ_DEV_CFG_APB_BASEADDR 0xF8007000 +#define ZYNQ_SCU_BASEADDR 0xF8F00000
/* Reflect slcr offsets */ struct slcr_regs { @@ -49,7 +49,7 @@ struct slcr_regs { u32 ocm_cfg; /* 0x910 */ };
-#define slcr_base ((struct slcr_regs *) XPSS_SYS_CTRL_BASEADDR) +#define slcr_base ((struct slcr_regs *)ZYNQ_SYS_CTRL_BASEADDR)
struct devcfg_regs { u32 ctrl; /* 0x0 */ @@ -72,7 +72,7 @@ struct devcfg_regs { u32 read_count; /* 0x8c */ };
-#define devcfg_base ((struct devcfg_regs *) XPSS_DEV_CFG_APB_BASEADDR) +#define devcfg_base ((struct devcfg_regs *)ZYNQ_DEV_CFG_APB_BASEADDR)
struct scu_regs { u32 reserved1[16]; @@ -80,6 +80,6 @@ struct scu_regs { u32 filter_end; /* 0x44 */ };
-#define scu_base ((struct scu_regs *) XPSS_SCU_BASEADDR) +#define scu_base ((struct scu_regs *)ZYNQ_SCU_BASEADDR)
#endif /* _ASM_ARCH_HARDWARE_H */ -- 1.8.2.1

Move baseaddr to hardware.h to be shared between configurations.
Signed-off-by: Michal Simek michal.simek@xilinx.com
--- Changes in v2: - Remove CONFIG_ prefix from non configurable macros (scutimer)
arch/arm/cpu/armv7/zynq/timer.c | 3 ++- arch/arm/include/asm/arch-zynq/hardware.h | 1 + include/configs/zynq.h | 3 --- 3 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/arch/arm/cpu/armv7/zynq/timer.c b/arch/arm/cpu/armv7/zynq/timer.c index 5d8bb24..8c4357d 100644 --- a/arch/arm/cpu/armv7/zynq/timer.c +++ b/arch/arm/cpu/armv7/zynq/timer.c @@ -44,6 +44,7 @@ #include <common.h> #include <div64.h> #include <asm/io.h> +#include <asm/arch/hardware.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -54,7 +55,7 @@ struct scu_timer { };
static struct scu_timer *timer_base = - (struct scu_timer *) CONFIG_SCUTIMER_BASEADDR; + (struct scu_timer *)ZYNQ_SCUTIMER_BASEADDR;
#define SCUTIMER_CONTROL_PRESCALER_MASK 0x0000FF00 /* Prescaler */ #define SCUTIMER_CONTROL_PRESCALER_SHIFT 8 diff --git a/arch/arm/include/asm/arch-zynq/hardware.h b/arch/arm/include/asm/arch-zynq/hardware.h index a99edbe..ccbf54e 100644 --- a/arch/arm/include/asm/arch-zynq/hardware.h +++ b/arch/arm/include/asm/arch-zynq/hardware.h @@ -26,6 +26,7 @@ #define ZYNQ_SYS_CTRL_BASEADDR 0xF8000000 #define ZYNQ_DEV_CFG_APB_BASEADDR 0xF8007000 #define ZYNQ_SCU_BASEADDR 0xF8F00000 +#define ZYNQ_SCUTIMER_BASEADDR 0xF8F00600
/* Reflect slcr offsets */ struct slcr_regs { diff --git a/include/configs/zynq.h b/include/configs/zynq.h index 2989e72..1147689 100644 --- a/include/configs/zynq.h +++ b/include/configs/zynq.h @@ -50,9 +50,6 @@ #define CONFIG_ZYNQ_SERIAL_BAUDRATE0 CONFIG_BAUDRATE #define CONFIG_ZYNQ_SERIAL_CLOCK0 50000000
-/* SCU timer address is hardcoded */ -#define CONFIG_SCUTIMER_BASEADDR 0xF8F00600 - /* Ethernet driver */ #define CONFIG_NET_MULTI #define CONFIG_ZYNQ_GEM -- 1.8.2.1

From: Michal Simek monstr@monstr.eu
This phy is used on zedboard (xilinx zynq platform).
Signed-off-by: Michal Simek monstr@monstr.eu Signed-off-by: Michal Simek michal.simek@xilinx.com --- Changes in v2: None
drivers/net/phy/marvell.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 4b27198..46801c7 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -465,6 +465,16 @@ static struct phy_driver M88E1149S_driver = { .shutdown = &genphy_shutdown, };
+static struct phy_driver M88E1518_driver = { + .name = "Marvell 88E1518", + .uid = 0x1410dd1, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1111s_config, + .startup = &m88e1011s_startup, + .shutdown = &genphy_shutdown, +}; + int phy_marvell_init(void) { phy_register(&M88E1149S_driver); @@ -474,6 +484,7 @@ int phy_marvell_init(void) phy_register(&M88E1118R_driver); phy_register(&M88E1111S_driver); phy_register(&M88E1011S_driver); + phy_register(&M88E1518_driver);
return 0; } -- 1.8.2.1

From: Michal Simek monstr@monstr.eu
Removing this bit causes that frame is sent only once. (With wrap big one packet has been sent several times which dramatically decrease throughput)
TRM: (Table 16-3: Tx Buffer Descriptor Entry)
Signed-off-by: Michal Simek monstr@monstr.eu Signed-off-by: Michal Simek michal.simek@xilinx.com --- Changes in v2: None
drivers/net/zynq_gem.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 3596065..7188b9e 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -310,8 +310,7 @@ static int zynq_gem_send(struct eth_device *dev, void *ptr, int len) memset((void *) &(priv->tx_bd), 0, sizeof(struct emac_bd));
priv->tx_bd.addr = (u32)ptr; - priv->tx_bd.status = len | ZYNQ_GEM_TXBUF_LAST_MASK | - ZYNQ_GEM_TXBUF_WRAP_MASK; + priv->tx_bd.status = len | ZYNQ_GEM_TXBUF_LAST_MASK;
/* Start transmit */ setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_STARTTX_MASK); -- 1.8.2.1

Remove one return from the code.
Signed-off-by: Michal Simek michal.simek@xilinx.com --- Changes in v2: None
drivers/net/zynq_gem.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 7188b9e..c0da628 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -363,11 +363,9 @@ static int zynq_gem_recv(struct eth_device *dev)
if ((++priv->rxbd_current) >= RX_BUF) priv->rxbd_current = 0; - - return frame_len; }
- return 0; + return frame_len; }
static void zynq_gem_halt(struct eth_device *dev) -- 1.8.2.1

BDs can be correctly setup just once and init function performs only phy autodetection and enabling RX/TX. RX/TX are disabled in halt function.
This patch solves the problem with repeatable tftp transfers.
Signed-off-by: Michal Simek michal.simek@xilinx.com --- Changes in v2: None
drivers/net/zynq_gem.c | 86 +++++++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 39 deletions(-)
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index c0da628..7758cf8 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -134,6 +134,7 @@ struct zynq_gem_priv { u32 rxbd_current; u32 rx_first_buf; int phyaddr; + int init; struct phy_device *phydev; struct mii_dev *bus; }; @@ -239,50 +240,57 @@ static int zynq_gem_init(struct eth_device *dev, bd_t * bis) SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full;
- /* Disable all interrupts */ - writel(0xFFFFFFFF, ®s->idr); - - /* Disable the receiver & transmitter */ - writel(0, ®s->nwctrl); - writel(0, ®s->txsr); - writel(0, ®s->rxsr); - writel(0, ®s->phymntnc); - - /* Clear the Hash registers for the mac address pointed by AddressPtr */ - writel(0x0, ®s->hashl); - /* Write bits [63:32] in TOP */ - writel(0x0, ®s->hashh); - - /* Clear all counters */ - for (i = 0; i <= stat_size; i++) - readl(®s->stat[i]); - - /* Setup RxBD space */ - memset(&(priv->rx_bd), 0, sizeof(priv->rx_bd)); - /* Create the RxBD ring */ - memset(&(priv->rxbuffers), 0, sizeof(priv->rxbuffers)); - - for (i = 0; i < RX_BUF; i++) { - priv->rx_bd[i].status = 0xF0000000; - priv->rx_bd[i].addr = (u32)((char *) &(priv->rxbuffers) + + if (!priv->init) { + /* Disable all interrupts */ + writel(0xFFFFFFFF, ®s->idr); + + /* Disable the receiver & transmitter */ + writel(0, ®s->nwctrl); + writel(0, ®s->txsr); + writel(0, ®s->rxsr); + writel(0, ®s->phymntnc); + + /* Clear the Hash registers for the mac address + * pointed by AddressPtr + */ + writel(0x0, ®s->hashl); + /* Write bits [63:32] in TOP */ + writel(0x0, ®s->hashh); + + /* Clear all counters */ + for (i = 0; i <= stat_size; i++) + readl(®s->stat[i]); + + /* Setup RxBD space */ + memset(&(priv->rx_bd), 0, sizeof(priv->rx_bd)); + /* Create the RxBD ring */ + memset(&(priv->rxbuffers), 0, sizeof(priv->rxbuffers)); + + for (i = 0; i < RX_BUF; i++) { + priv->rx_bd[i].status = 0xF0000000; + priv->rx_bd[i].addr = + (u32)((char *)&(priv->rxbuffers) + (i * PKTSIZE_ALIGN)); - } - /* WRAP bit to last BD */ - priv->rx_bd[--i].addr |= ZYNQ_GEM_RXBUF_WRAP_MASK; - /* Write RxBDs to IP */ - writel((u32) &(priv->rx_bd), ®s->rxqbase); + } + /* WRAP bit to last BD */ + priv->rx_bd[--i].addr |= ZYNQ_GEM_RXBUF_WRAP_MASK; + /* Write RxBDs to IP */ + writel((u32)&(priv->rx_bd), ®s->rxqbase);
- /* MAC Setup */ - /* Setup Network Configuration register */ - writel(ZYNQ_GEM_NWCFG_INIT, ®s->nwcfg); + /* MAC Setup */ + /* Setup Network Configuration register */ + writel(ZYNQ_GEM_NWCFG_INIT, ®s->nwcfg);
- /* Setup for DMA Configuration register */ - writel(ZYNQ_GEM_DMACR_INIT, ®s->dmacr); + /* Setup for DMA Configuration register */ + writel(ZYNQ_GEM_DMACR_INIT, ®s->dmacr);
- /* Setup for Network Control register, MDIO, Rx and Tx enable */ - setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_MDEN_MASK | + /* Setup for Network Control register, MDIO, Rx and Tx enable */ + setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_MDEN_MASK | ZYNQ_GEM_NWCTRL_RXEN_MASK | ZYNQ_GEM_NWCTRL_TXEN_MASK);
+ priv->init++; + } + /* interface - look at tsec */ phydev = phy_connect(priv->bus, priv->phyaddr, dev, 0);
@@ -307,7 +315,7 @@ static int zynq_gem_send(struct eth_device *dev, void *ptr, int len) writel((u32)&(priv->tx_bd), ®s->txqbase);
/* Setup Tx BD */ - memset((void *) &(priv->tx_bd), 0, sizeof(struct emac_bd)); + memset((void *)&(priv->tx_bd), 0, sizeof(struct emac_bd));
priv->tx_bd.addr = (u32)ptr; priv->tx_bd.status = len | ZYNQ_GEM_TXBUF_LAST_MASK; -- 1.8.2.1

From: Michal Simek monstr@monstr.eu
The whole driver used 100Mbps because of zc702 rev B. Fix problem with not setup proper clock for gem1. This is generic approach for clk setup.
Signed-off-by: Michal Simek monstr@monstr.eu Signed-off-by: Michal Simek michal.simek@xilinx.com --- Changes in v2: None
arch/arm/cpu/armv7/zynq/slcr.c | 26 +++++++++++++++ arch/arm/include/asm/arch-zynq/hardware.h | 7 +++- arch/arm/include/asm/arch-zynq/sys_proto.h | 1 + drivers/net/zynq_gem.c | 53 +++++++++++++++++++++--------- 4 files changed, 71 insertions(+), 16 deletions(-)
diff --git a/arch/arm/cpu/armv7/zynq/slcr.c b/arch/arm/cpu/armv7/zynq/slcr.c index 788a8fd..5a8674a 100644 --- a/arch/arm/cpu/armv7/zynq/slcr.c +++ b/arch/arm/cpu/armv7/zynq/slcr.c @@ -61,3 +61,29 @@ void zynq_slcr_cpu_reset(void)
writel(1, &slcr_base->pss_rst_ctrl); } + +/* Setup clk for network */ +void zynq_slcr_gem_clk_setup(u32 gem_id, u32 rclk, u32 clk) +{ + zynq_slcr_unlock(); + + if (gem_id > 1) { + printf("Non existing GEM id %d\n", gem_id); + goto out; + } + + if (gem_id) { + /* Set divisors for appropriate frequency in GEM_CLK_CTRL */ + writel(clk, &slcr_base->gem1_clk_ctrl); + /* Configure GEM_RCLK_CTRL */ + writel(rclk, &slcr_base->gem1_rclk_ctrl); + } else { + /* Set divisors for appropriate frequency in GEM_CLK_CTRL */ + writel(clk, &slcr_base->gem0_clk_ctrl); + /* Configure GEM_RCLK_CTRL */ + writel(rclk, &slcr_base->gem0_rclk_ctrl); + } + +out: + zynq_slcr_lock(); +} diff --git a/arch/arm/include/asm/arch-zynq/hardware.h b/arch/arm/include/asm/arch-zynq/hardware.h index ccbf54e..d8e378f 100644 --- a/arch/arm/include/asm/arch-zynq/hardware.h +++ b/arch/arm/include/asm/arch-zynq/hardware.h @@ -33,7 +33,12 @@ struct slcr_regs { u32 scl; /* 0x0 */ u32 slcr_lock; /* 0x4 */ u32 slcr_unlock; /* 0x8 */ - u32 reserved1[125]; + u32 reserved0[75]; + u32 gem0_rclk_ctrl; /* 0x138 */ + u32 gem1_rclk_ctrl; /* 0x13c */ + u32 gem0_clk_ctrl; /* 0x140 */ + u32 gem1_clk_ctrl; /* 0x144 */ + u32 reserved1[46]; u32 pss_rst_ctrl; /* 0x200 */ u32 reserved2[15]; u32 fpga_rst_ctrl; /* 0x240 */ diff --git a/arch/arm/include/asm/arch-zynq/sys_proto.h b/arch/arm/include/asm/arch-zynq/sys_proto.h index e788900..57128dc 100644 --- a/arch/arm/include/asm/arch-zynq/sys_proto.h +++ b/arch/arm/include/asm/arch-zynq/sys_proto.h @@ -26,5 +26,6 @@ extern void zynq_slcr_lock(void); extern void zynq_slcr_unlock(void); extern void zynq_slcr_cpu_reset(void); +extern void zynq_slcr_gem_clk_setup(u32 gem_id, u32 rclk, u32 clk);
#endif /* _SYS_PROTO_H_ */ diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 7758cf8..2d717e9 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -33,6 +33,7 @@ #include <phy.h> #include <miiphy.h> #include <watchdog.h> +#include <asm/arch/sys_proto.h>
#if !defined(CONFIG_PHYLIB) # error XILINX_GEM_ETHERNET requires PHYLIB @@ -67,13 +68,14 @@ #define ZYNQ_GEM_NWCTRL_MDEN_MASK 0x00000010 /* Enable MDIO port */ #define ZYNQ_GEM_NWCTRL_STARTTX_MASK 0x00000200 /* Start tx (tx_go) */
-#define ZYNQ_GEM_NWCFG_SPEED 0x00000001 /* 100 Mbps operation */ -#define ZYNQ_GEM_NWCFG_FDEN 0x00000002 /* Full Duplex mode */ -#define ZYNQ_GEM_NWCFG_FSREM 0x00020000 /* FCS removal */ +#define ZYNQ_GEM_NWCFG_SPEED100 0x000000001 /* 100 Mbps operation */ +#define ZYNQ_GEM_NWCFG_SPEED1000 0x000000400 /* 1Gbps operation */ +#define ZYNQ_GEM_NWCFG_FDEN 0x000000002 /* Full Duplex mode */ +#define ZYNQ_GEM_NWCFG_FSREM 0x000020000 /* FCS removal */ #define ZYNQ_GEM_NWCFG_MDCCLKDIV 0x000080000 /* Div pclk by 32, 80MHz */ +#define ZYNQ_GEM_NWCFG_MDCCLKDIV2 0x0000c0000 /* Div pclk by 48, 120MHz */
-#define ZYNQ_GEM_NWCFG_INIT (ZYNQ_GEM_NWCFG_SPEED | \ - ZYNQ_GEM_NWCFG_FDEN | \ +#define ZYNQ_GEM_NWCFG_INIT (ZYNQ_GEM_NWCFG_FDEN | \ ZYNQ_GEM_NWCFG_FSREM | \ ZYNQ_GEM_NWCFG_MDCCLKDIV)
@@ -227,7 +229,7 @@ static int zynq_gem_setup_mac(struct eth_device *dev)
static int zynq_gem_init(struct eth_device *dev, bd_t * bis) { - u32 i; + u32 i, rclk, clk = 0; struct phy_device *phydev; const u32 stat_size = (sizeof(struct zynq_gem_regs) - offsetof(struct zynq_gem_regs, stat)) / 4; @@ -277,16 +279,11 @@ static int zynq_gem_init(struct eth_device *dev, bd_t * bis) /* Write RxBDs to IP */ writel((u32)&(priv->rx_bd), ®s->rxqbase);
- /* MAC Setup */ - /* Setup Network Configuration register */ - writel(ZYNQ_GEM_NWCFG_INIT, ®s->nwcfg); - /* Setup for DMA Configuration register */ writel(ZYNQ_GEM_DMACR_INIT, ®s->dmacr);
/* Setup for Network Control register, MDIO, Rx and Tx enable */ - setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_MDEN_MASK | - ZYNQ_GEM_NWCTRL_RXEN_MASK | ZYNQ_GEM_NWCTRL_TXEN_MASK); + setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_MDEN_MASK);
priv->init++; } @@ -294,12 +291,38 @@ static int zynq_gem_init(struct eth_device *dev, bd_t * bis) /* interface - look at tsec */ phydev = phy_connect(priv->bus, priv->phyaddr, dev, 0);
- phydev->supported &= supported; + phydev->supported = supported | ADVERTISED_Pause | + ADVERTISED_Asym_Pause; phydev->advertising = phydev->supported; priv->phydev = phydev; phy_config(phydev); phy_startup(phydev);
+ switch (phydev->speed) { + case SPEED_1000: + writel(ZYNQ_GEM_NWCFG_INIT | ZYNQ_GEM_NWCFG_SPEED1000, + ®s->nwcfg); + rclk = (0 << 4) | (1 << 0); + clk = (1 << 20) | (8 << 8) | (0 << 4) | (1 << 0); + break; + case SPEED_100: + clrsetbits_le32(®s->nwcfg, ZYNQ_GEM_NWCFG_SPEED1000, + ZYNQ_GEM_NWCFG_INIT | ZYNQ_GEM_NWCFG_SPEED100); + rclk = 1 << 0; + clk = (5 << 20) | (8 << 8) | (0 << 4) | (1 << 0); + break; + case SPEED_10: + rclk = 1 << 0; + /* FIXME untested */ + clk = (5 << 20) | (8 << 8) | (0 << 4) | (1 << 0); + break; + } + /* FIXME maybe better to define gem address in hardware.h */ + zynq_slcr_gem_clk_setup(dev->iobase != 0xE000B000, rclk, clk); + + setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK | + ZYNQ_GEM_NWCTRL_TXEN_MASK); + return 0; }
@@ -380,8 +403,8 @@ static void zynq_gem_halt(struct eth_device *dev) { struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase;
- /* Disable the receiver & transmitter */ - writel(0, ®s->nwctrl); + clrsetbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK | + ZYNQ_GEM_NWCTRL_TXEN_MASK, 0); }
static int zynq_gem_miiphyread(const char *devname, uchar addr, -- 1.8.2.1

Add all fixed addresses to hardware.h and change petalinux configuration to support this.
Signed-off-by: Michal Simek michal.simek@xilinx.com --- Changes in v2: - Remove CONFIG_ prefix from non configurable macro (gem)
arch/arm/include/asm/arch-zynq/hardware.h | 2 ++ board/xilinx/zynq/board.c | 12 +++++++++--- include/configs/zynq.h | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/arch/arm/include/asm/arch-zynq/hardware.h b/arch/arm/include/asm/arch-zynq/hardware.h index d8e378f..5820f3b 100644 --- a/arch/arm/include/asm/arch-zynq/hardware.h +++ b/arch/arm/include/asm/arch-zynq/hardware.h @@ -27,6 +27,8 @@ #define ZYNQ_DEV_CFG_APB_BASEADDR 0xF8007000 #define ZYNQ_SCU_BASEADDR 0xF8F00000 #define ZYNQ_SCUTIMER_BASEADDR 0xF8F00600 +#define ZYNQ_GEM_BASEADDR0 0xE000B000 +#define ZYNQ_GEM_BASEADDR1 0xE000C000
/* Reflect slcr offsets */ struct slcr_regs { diff --git a/board/xilinx/zynq/board.c b/board/xilinx/zynq/board.c index 8ed75c3..3af18f0 100644 --- a/board/xilinx/zynq/board.c +++ b/board/xilinx/zynq/board.c @@ -22,6 +22,8 @@
#include <common.h> #include <netdev.h> +#include <asm/arch/hardware.h> +#include <asm/arch/sys_proto.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -38,10 +40,14 @@ int board_eth_init(bd_t *bis) { u32 ret = 0;
-#if defined(CONFIG_ZYNQ_GEM) && defined(CONFIG_ZYNQ_GEM_BASEADDR0) - ret = zynq_gem_initialize(bis, CONFIG_ZYNQ_GEM_BASEADDR0); +#if defined(CONFIG_ZYNQ_GEM) +# if defined(CONFIG_ZYNQ_GEM0) + ret |= zynq_gem_initialize(bis, ZYNQ_GEM_BASEADDR0); +# endif +# if defined(CONFIG_ZYNQ_GEM1) + ret |= zynq_gem_initialize(bis, ZYNQ_GEM_BASEADDR1); +# endif #endif - return ret; } #endif diff --git a/include/configs/zynq.h b/include/configs/zynq.h index 1147689..ebe1b1b 100644 --- a/include/configs/zynq.h +++ b/include/configs/zynq.h @@ -53,7 +53,7 @@ /* Ethernet driver */ #define CONFIG_NET_MULTI #define CONFIG_ZYNQ_GEM -#define CONFIG_ZYNQ_GEM_BASEADDR0 0xE000B000 +#define CONFIG_ZYNQ_GEM0
#if defined(CONFIG_ZYNQ_DCC) # define CONFIG_ARM_DCC -- 1.8.2.1

From: David Andrey david.andrey@netmodule.com
Pass the PHY address to the driver init to allow parallel use of both interfaces
Signed-off-by: David Andrey david.andrey@netmodule.com Signed-off-by: Michal Simek michal.simek@xilinx.com --- Changes in v2: None
board/xilinx/zynq/board.c | 6 ++++-- drivers/net/zynq_gem.c | 8 ++------ include/configs/zynq.h | 1 + include/netdev.h | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/board/xilinx/zynq/board.c b/board/xilinx/zynq/board.c index 3af18f0..546adc8 100644 --- a/board/xilinx/zynq/board.c +++ b/board/xilinx/zynq/board.c @@ -42,10 +42,12 @@ int board_eth_init(bd_t *bis)
#if defined(CONFIG_ZYNQ_GEM) # if defined(CONFIG_ZYNQ_GEM0) - ret |= zynq_gem_initialize(bis, ZYNQ_GEM_BASEADDR0); + ret |= zynq_gem_initialize(bis, ZYNQ_GEM_BASEADDR0, + CONFIG_ZYNQ_GEM_PHY_ADDR0); # endif # if defined(CONFIG_ZYNQ_GEM1) - ret |= zynq_gem_initialize(bis, ZYNQ_GEM_BASEADDR1); + ret |= zynq_gem_initialize(bis, ZYNQ_GEM_BASEADDR1, + CONFIG_ZYNQ_GEM_PHY_ADDR1); # endif #endif return ret; diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 2d717e9..316816d 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -427,7 +427,7 @@ static int zynq_gem_miiphy_write(const char *devname, uchar addr, return phywrite(dev, addr, reg, val); }
-int zynq_gem_initialize(bd_t *bis, int base_addr) +int zynq_gem_initialize(bd_t *bis, int base_addr, int phy_addr) { struct eth_device *dev; struct zynq_gem_priv *priv; @@ -443,11 +443,7 @@ int zynq_gem_initialize(bd_t *bis, int base_addr) } priv = dev->priv;
-#ifdef CONFIG_PHY_ADDR - priv->phyaddr = CONFIG_PHY_ADDR; -#else - priv->phyaddr = -1; -#endif + priv->phyaddr = phy_addr;
sprintf(dev->name, "Gem.%x", base_addr);
diff --git a/include/configs/zynq.h b/include/configs/zynq.h index ebe1b1b..3b23354 100644 --- a/include/configs/zynq.h +++ b/include/configs/zynq.h @@ -54,6 +54,7 @@ #define CONFIG_NET_MULTI #define CONFIG_ZYNQ_GEM #define CONFIG_ZYNQ_GEM0 +#define CONFIG_ZYNQ_GEM_PHY_ADDR0 7
#if defined(CONFIG_ZYNQ_DCC) # define CONFIG_ARM_DCC diff --git a/include/netdev.h b/include/netdev.h index fd3e243..81117b1 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -104,7 +104,7 @@ int xilinx_emaclite_initialize(bd_t *bis, unsigned long base_addr, int txpp, int rxpp); int xilinx_ll_temac_eth_init(bd_t *bis, unsigned long base_addr, int flags, unsigned long ctrl_addr); -int zynq_gem_initialize(bd_t *bis, int base_addr); +int zynq_gem_initialize(bd_t *bis, int base_addr, int phy_addr); /* * As long as the Xilinx xps_ll_temac ethernet driver has not its own interface * exported by a public hader file, we need a global definition at this point. -- 1.8.2.1

From: David Andrey david.andrey@netmodule.com
Avoid overwriting GEMx_RCLK_CTRL and GEMx_CLK_CTRL if the Ethernet interface is connect on EMIO
Do not enable emio for this standard board configuration for now.
Signed-off-by: David Andrey david.andrey@netmodule.com Signed-off-by: Michal Simek michal.simek@xilinx.com --- Changes in v2: - Remove CONFIG_ prefix from non configurable macros (emio)
board/xilinx/zynq/board.c | 4 ++-- drivers/net/zynq_gem.c | 12 +++++++++--- include/netdev.h | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/board/xilinx/zynq/board.c b/board/xilinx/zynq/board.c index 546adc8..57d8f53 100644 --- a/board/xilinx/zynq/board.c +++ b/board/xilinx/zynq/board.c @@ -43,11 +43,11 @@ int board_eth_init(bd_t *bis) #if defined(CONFIG_ZYNQ_GEM) # if defined(CONFIG_ZYNQ_GEM0) ret |= zynq_gem_initialize(bis, ZYNQ_GEM_BASEADDR0, - CONFIG_ZYNQ_GEM_PHY_ADDR0); + CONFIG_ZYNQ_GEM_PHY_ADDR0, 0); # endif # if defined(CONFIG_ZYNQ_GEM1) ret |= zynq_gem_initialize(bis, ZYNQ_GEM_BASEADDR1, - CONFIG_ZYNQ_GEM_PHY_ADDR1); + CONFIG_ZYNQ_GEM_PHY_ADDR1, 0); # endif #endif return ret; diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 316816d..8e0e01c 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -33,6 +33,7 @@ #include <phy.h> #include <miiphy.h> #include <watchdog.h> +#include <asm/arch/hardware.h> #include <asm/arch/sys_proto.h>
#if !defined(CONFIG_PHYLIB) @@ -136,6 +137,7 @@ struct zynq_gem_priv { u32 rxbd_current; u32 rx_first_buf; int phyaddr; + u32 emio; int init; struct phy_device *phydev; struct mii_dev *bus; @@ -317,8 +319,11 @@ static int zynq_gem_init(struct eth_device *dev, bd_t * bis) clk = (5 << 20) | (8 << 8) | (0 << 4) | (1 << 0); break; } - /* FIXME maybe better to define gem address in hardware.h */ - zynq_slcr_gem_clk_setup(dev->iobase != 0xE000B000, rclk, clk); + + /* Change the rclk and clk only not using EMIO interface */ + if (!priv->emio) + zynq_slcr_gem_clk_setup(dev->iobase != + ZYNQ_GEM_BASEADDR0, rclk, clk);
setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK | ZYNQ_GEM_NWCTRL_TXEN_MASK); @@ -427,7 +432,7 @@ static int zynq_gem_miiphy_write(const char *devname, uchar addr, return phywrite(dev, addr, reg, val); }
-int zynq_gem_initialize(bd_t *bis, int base_addr, int phy_addr) +int zynq_gem_initialize(bd_t *bis, int base_addr, int phy_addr, u32 emio) { struct eth_device *dev; struct zynq_gem_priv *priv; @@ -444,6 +449,7 @@ int zynq_gem_initialize(bd_t *bis, int base_addr, int phy_addr) priv = dev->priv;
priv->phyaddr = phy_addr; + priv->emio = emio;
sprintf(dev->name, "Gem.%x", base_addr);
diff --git a/include/netdev.h b/include/netdev.h index 81117b1..516b351 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -104,7 +104,7 @@ int xilinx_emaclite_initialize(bd_t *bis, unsigned long base_addr, int txpp, int rxpp); int xilinx_ll_temac_eth_init(bd_t *bis, unsigned long base_addr, int flags, unsigned long ctrl_addr); -int zynq_gem_initialize(bd_t *bis, int base_addr, int phy_addr); +int zynq_gem_initialize(bd_t *bis, int base_addr, int phy_addr, u32 emio); /* * As long as the Xilinx xps_ll_temac ethernet driver has not its own interface * exported by a public hader file, we need a global definition at this point. -- 1.8.2.1

Autodetect phy if phyaddress is setup to -1.
Signed-off-by: Michal Simek michal.simek@xilinx.com --- Changes in v2: None
drivers/net/zynq_gem.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+)
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 8e0e01c..eac9b6f 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -95,6 +95,17 @@ ZYNQ_GEM_DMACR_TXSIZE | \ ZYNQ_GEM_DMACR_RXBUF)
+/* Use MII register 1 (MII status register) to detect PHY */ +#define PHY_DETECT_REG 1 + +/* Mask used to verify certain PHY features (or register contents) + * in the register above: + * 0x1000: 10Mbps full duplex support + * 0x0800: 10Mbps half duplex support + * 0x0008: Auto-negotiation support + */ +#define PHY_DETECT_MASK 0x1808 + /* Device registers */ struct zynq_gem_regs { u32 nwctrl; /* Network Control reg */ @@ -201,6 +212,44 @@ static u32 phywrite(struct eth_device *dev, u32 phy_addr, u32 regnum, u16 data) ZYNQ_GEM_PHYMNTNC_OP_W_MASK, &data); }
+static void phy_detection(struct eth_device *dev) +{ + int i; + u16 phyreg; + struct zynq_gem_priv *priv = dev->priv; + + if (priv->phyaddr != -1) { + phyread(dev, priv->phyaddr, PHY_DETECT_REG, &phyreg); + if ((phyreg != 0xFFFF) && + ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) { + /* Found a valid PHY address */ + debug("Default phy address %d is valid\n", + priv->phyaddr); + return; + } else { + debug("PHY address is not setup correctly %d\n", + priv->phyaddr); + priv->phyaddr = -1; + } + } + + debug("detecting phy address\n"); + if (priv->phyaddr == -1) { + /* detect the PHY address */ + for (i = 31; i >= 0; i--) { + phyread(dev, i, PHY_DETECT_REG, &phyreg); + if ((phyreg != 0xFFFF) && + ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) { + /* Found a valid PHY address */ + priv->phyaddr = i; + debug("Found valid phy address, %d\n", i); + return; + } + } + } + printf("PHY is not detected\n"); +} + static int zynq_gem_setup_mac(struct eth_device *dev) { u32 i, macaddrlow, macaddrhigh; @@ -290,6 +339,8 @@ static int zynq_gem_init(struct eth_device *dev, bd_t * bis) priv->init++; }
+ phy_detection(dev); + /* interface - look at tsec */ phydev = phy_connect(priv->bus, priv->phyaddr, dev, 0);
-- 1.8.2.1

Add support for SD, MMC and eMMC card on Xilinx Zynq.
Signed-off-by: Michal Simek michal.simek@xilinx.com --- Changes in v2: - Remove CONFIG_ prefix from non configurable macros (sdhci)
arch/arm/include/asm/arch-zynq/hardware.h | 2 ++ arch/arm/include/asm/arch-zynq/sys_proto.h | 3 +++ board/xilinx/zynq/board.c | 17 +++++++++++++ drivers/mmc/Makefile | 1 + drivers/mmc/zynq_sdhci.c | 40 ++++++++++++++++++++++++++++++ include/configs/zynq.h | 16 ++++++++++++ 6 files changed, 79 insertions(+) create mode 100644 drivers/mmc/zynq_sdhci.c
diff --git a/arch/arm/include/asm/arch-zynq/hardware.h b/arch/arm/include/asm/arch-zynq/hardware.h index 5820f3b..8eb4e1a 100644 --- a/arch/arm/include/asm/arch-zynq/hardware.h +++ b/arch/arm/include/asm/arch-zynq/hardware.h @@ -29,6 +29,8 @@ #define ZYNQ_SCUTIMER_BASEADDR 0xF8F00600 #define ZYNQ_GEM_BASEADDR0 0xE000B000 #define ZYNQ_GEM_BASEADDR1 0xE000C000 +#define ZYNQ_SDHCI_BASEADDR0 0xE0100000 +#define ZYNQ_SDHCI_BASEADDR1 0xE0101000
/* Reflect slcr offsets */ struct slcr_regs { diff --git a/arch/arm/include/asm/arch-zynq/sys_proto.h b/arch/arm/include/asm/arch-zynq/sys_proto.h index 57128dc..af9e7f8 100644 --- a/arch/arm/include/asm/arch-zynq/sys_proto.h +++ b/arch/arm/include/asm/arch-zynq/sys_proto.h @@ -28,4 +28,7 @@ extern void zynq_slcr_unlock(void); extern void zynq_slcr_cpu_reset(void); extern void zynq_slcr_gem_clk_setup(u32 gem_id, u32 rclk, u32 clk);
+/* Driver extern functions */ +extern int zynq_sdhci_init(u32 regbase); + #endif /* _SYS_PROTO_H_ */ diff --git a/board/xilinx/zynq/board.c b/board/xilinx/zynq/board.c index 57d8f53..1589d21 100644 --- a/board/xilinx/zynq/board.c +++ b/board/xilinx/zynq/board.c @@ -54,6 +54,23 @@ int board_eth_init(bd_t *bis) } #endif
+#ifdef CONFIG_CMD_MMC +int board_mmc_init(bd_t *bd) +{ + int ret = 0; + +#if defined(CONFIG_ZYNQ_SDHCI) +# if defined(CONFIG_ZYNQ_SDHCI0) + ret = zynq_sdhci_init(ZYNQ_SDHCI_BASEADDR0); +# endif +# if defined(CONFIG_ZYNQ_SDHCI1) + ret |= zynq_sdhci_init(ZYNQ_SDHCI_BASEADDR1); +# endif +#endif + return ret; +} +#endif + int dram_init(void) { gd->ram_size = CONFIG_SYS_SDRAM_SIZE; diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 1d6faa2..7cd4281 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -49,6 +49,7 @@ COBJS-$(CONFIG_SH_MMCIF) += sh_mmcif.o COBJS-$(CONFIG_TEGRA_MMC) += tegra_mmc.o COBJS-$(CONFIG_DWMMC) += dw_mmc.o COBJS-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o +COBJS-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c new file mode 100644 index 0000000..9e37af4 --- /dev/null +++ b/drivers/mmc/zynq_sdhci.c @@ -0,0 +1,40 @@ +/* + * (C) Copyright 2013 Inc. + * + * Xilinx Zynq SD Host Controller Interface + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <common.h> +#include <malloc.h> +#include <sdhci.h> +#include <asm/arch/sys_proto.h> + +int zynq_sdhci_init(u32 regbase) +{ + struct sdhci_host *host = NULL; + + host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); + if (!host) { + printf("zynq_sdhci_init: sdhci_host malloc fail\n"); + return 1; + } + + host->name = "zynq_sdhci"; + host->ioaddr = (void *)regbase; + host->quirks = SDHCI_QUIRK_NO_CD | SDHCI_QUIRK_WAIT_SEND_CMD; + host->version = sdhci_readw(host, SDHCI_HOST_VERSION); + + host->host_caps = MMC_MODE_HC; + + add_sdhci(host, 52000000, 52000000 >> 9); + return 0; +} diff --git a/include/configs/zynq.h b/include/configs/zynq.h index 3b23354..2ed88a7 100644 --- a/include/configs/zynq.h +++ b/include/configs/zynq.h @@ -56,6 +56,22 @@ #define CONFIG_ZYNQ_GEM0 #define CONFIG_ZYNQ_GEM_PHY_ADDR0 7
+#define CONFIG_ZYNQ_SDHCI +#define CONFIG_ZYNQ_SDHCI0 + +/* MMC */ +#if defined(CONFIG_ZYNQ_SDHCI0) || defined(CONFIG_ZYNQ_SDHCI1) +# define CONFIG_MMC +# define CONFIG_GENERIC_MMC +# define CONFIG_SDHCI +# define CONFIG_ZYNQ_SDHCI +# define CONFIG_CMD_MMC +# define CONFIG_CMD_FAT +# define CONFIG_SUPPORT_VFAT +# define CONFIG_CMD_EXT2 +# define CONFIG_DOS_PARTITION +#endif + #if defined(CONFIG_ZYNQ_DCC) # define CONFIG_ARM_DCC # define CONFIG_CPU_V6 /* Required by CONFIG_ARM_DCC */ -- 1.8.2.1

Support Xilinx Zynq i2c controller.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Signed-off-by: Michal Simek michal.simek@xilinx.com CC: Heiko Schocher hs@denx.de --- Changes in v2: - Remove CONFIG_ prefix from non configurable macros (i2c) - Fix checkpatch warnings (i2c) - Fix #define<space>Macro name (i2c) - Fix multiline comments (i2c) - Remove trailing 1 for configurations (i2c)
arch/arm/include/asm/arch-zynq/hardware.h | 2 + drivers/i2c/Makefile | 1 + drivers/i2c/zynq_i2c.c | 306 ++++++++++++++++++++++++++++++ include/configs/zynq.h | 11 ++ 4 files changed, 320 insertions(+) create mode 100644 drivers/i2c/zynq_i2c.c
diff --git a/arch/arm/include/asm/arch-zynq/hardware.h b/arch/arm/include/asm/arch-zynq/hardware.h index 8eb4e1a..6af892a 100644 --- a/arch/arm/include/asm/arch-zynq/hardware.h +++ b/arch/arm/include/asm/arch-zynq/hardware.h @@ -31,6 +31,8 @@ #define ZYNQ_GEM_BASEADDR1 0xE000C000 #define ZYNQ_SDHCI_BASEADDR0 0xE0100000 #define ZYNQ_SDHCI_BASEADDR1 0xE0101000 +#define ZYNQ_I2C_BASEADDR0 0xE0004000 +#define ZYNQ_I2C_BASEADDR1 0xE0005000
/* Reflect slcr offsets */ struct slcr_regs { diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 5dbdbe3..72e85a3 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -46,6 +46,7 @@ COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o COBJS-$(CONFIG_U8500_I2C) += u8500_i2c.o COBJS-$(CONFIG_SH_I2C) += sh_i2c.o COBJS-$(CONFIG_SH_SH7734_I2C) += sh_sh7734_i2c.o +COBJS-$(CONFIG_ZYNQ_I2C) += zynq_i2c.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/i2c/zynq_i2c.c b/drivers/i2c/zynq_i2c.c new file mode 100644 index 0000000..ec49660 --- /dev/null +++ b/drivers/i2c/zynq_i2c.c @@ -0,0 +1,306 @@ +/* + * Driver for the Zynq-7000 PS I2C controller + * IP from Cadence (ID T-CS-PE-0007-100, Version R1p10f2) + * + * Author: Joe Hershberger joe.hershberger@ni.com + * Copyright (c) 2012 Joe Hershberger. + * + * Copyright (c) 2012-2013 Xilinx, Michal Simek + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <common.h> +#include <asm/io.h> +#include <i2c.h> +#include <asm/errno.h> +#include <asm/arch/hardware.h> + +/* i2c register set */ +struct zynq_i2c_registers { + u32 control; + u32 status; + u32 address; + u32 data; + u32 interrupt_status; + u32 transfer_size; + u32 slave_mon_pause; + u32 time_out; + u32 interrupt_mask; + u32 interrupt_enable; + u32 interrupt_disable; +}; + +/* Control register fields */ +#define ZYNQ_I2C_CONTROL_RW 0x00000001 +#define ZYNQ_I2C_CONTROL_MS 0x00000002 +#define ZYNQ_I2C_CONTROL_NEA 0x00000004 +#define ZYNQ_I2C_CONTROL_ACKEN 0x00000008 +#define ZYNQ_I2C_CONTROL_HOLD 0x00000010 +#define ZYNQ_I2C_CONTROL_SLVMON 0x00000020 +#define ZYNQ_I2C_CONTROL_CLR_FIFO 0x00000040 +#define ZYNQ_I2C_CONTROL_DIV_B_SHIFT 8 +#define ZYNQ_I2C_CONTROL_DIV_B_MASK 0x00003F00 +#define ZYNQ_I2C_CONTROL_DIV_A_SHIFT 14 +#define ZYNQ_I2C_CONTROL_DIV_A_MASK 0x0000C000 + +/* Status register values */ +#define ZYNQ_I2C_STATUS_RXDV 0x00000020 +#define ZYNQ_I2C_STATUS_TXDV 0x00000040 +#define ZYNQ_I2C_STATUS_RXOVF 0x00000080 +#define ZYNQ_I2C_STATUS_BA 0x00000100 + +/* Interrupt register fields */ +#define ZYNQ_I2C_INTERRUPT_COMP 0x00000001 +#define ZYNQ_I2C_INTERRUPT_DATA 0x00000002 +#define ZYNQ_I2C_INTERRUPT_NACK 0x00000004 +#define ZYNQ_I2C_INTERRUPT_TO 0x00000008 +#define ZYNQ_I2C_INTERRUPT_SLVRDY 0x00000010 +#define ZYNQ_I2C_INTERRUPT_RXOVF 0x00000020 +#define ZYNQ_I2C_INTERRUPT_TXOVF 0x00000040 +#define ZYNQ_I2C_INTERRUPT_RXUNF 0x00000080 +#define ZYNQ_I2C_INTERRUPT_ARBLOST 0x00000200 + +#define ZYNQ_I2C_FIFO_DEPTH 16 +#define ZYNQ_I2C_TRANSFERT_SIZE_MAX 255 /* Controller transfer limit */ + +#if defined(CONFIG_ZYNQ_I2C0) +# define ZYNQ_I2C_BASE ZYNQ_I2C_BASEADDR0 +#else +# define ZYNQ_I2C_BASE ZYNQ_I2C_BASEADDR1 +#endif + +static struct zynq_i2c_registers *zynq_i2c = + (struct zynq_i2c_registers *)ZYNQ_I2C_BASE; + +/* I2C init called by cmd_i2c when doing 'i2c reset'. */ +void i2c_init(int requested_speed, int slaveadd) +{ + /* 111MHz / ( (3 * 17) * 22 ) = ~100KHz */ + writel((16 << ZYNQ_I2C_CONTROL_DIV_B_SHIFT) | + (2 << ZYNQ_I2C_CONTROL_DIV_A_SHIFT), &zynq_i2c->control); + + /* Enable master mode, ack, and 7-bit addressing */ + setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_MS | + ZYNQ_I2C_CONTROL_ACKEN | ZYNQ_I2C_CONTROL_NEA); +} + +#ifdef DEBUG +static void zynq_i2c_debug_status(void) +{ + int int_status; + int status; + int_status = readl(&zynq_i2c->interrupt_status); + + status = readl(&zynq_i2c->status); + if (int_status || status) { + debug("Status: "); + if (int_status & ZYNQ_I2C_INTERRUPT_COMP) + debug("COMP "); + if (int_status & ZYNQ_I2C_INTERRUPT_DATA) + debug("DATA "); + if (int_status & ZYNQ_I2C_INTERRUPT_NACK) + debug("NACK "); + if (int_status & ZYNQ_I2C_INTERRUPT_TO) + debug("TO "); + if (int_status & ZYNQ_I2C_INTERRUPT_SLVRDY) + debug("SLVRDY "); + if (int_status & ZYNQ_I2C_INTERRUPT_RXOVF) + debug("RXOVF "); + if (int_status & ZYNQ_I2C_INTERRUPT_TXOVF) + debug("TXOVF "); + if (int_status & ZYNQ_I2C_INTERRUPT_RXUNF) + debug("RXUNF "); + if (int_status & ZYNQ_I2C_INTERRUPT_ARBLOST) + debug("ARBLOST "); + if (status & ZYNQ_I2C_STATUS_RXDV) + debug("RXDV "); + if (status & ZYNQ_I2C_STATUS_TXDV) + debug("TXDV "); + if (status & ZYNQ_I2C_STATUS_RXOVF) + debug("RXOVF "); + if (status & ZYNQ_I2C_STATUS_BA) + debug("BA "); + debug("TS%d ", readl(&zynq_i2c->transfer_size)); + debug("\n"); + } +} +#endif + +/* Wait for an interrupt */ +static u32 zynq_i2c_wait(u32 mask) +{ + int timeout, int_status; + + for (timeout = 0; timeout < 100; timeout++) { + udelay(100); + int_status = readl(&zynq_i2c->interrupt_status); + if (int_status & mask) + break; + } +#ifdef DEBUG + zynq_i2c_debug_status(); +#endif + /* Clear interrupt status flags */ + writel(int_status & mask, &zynq_i2c->interrupt_status); + + return int_status & mask; +} + +/* + * I2C probe called by cmd_i2c when doing 'i2c probe'. + * Begin read, nak data byte, end. + */ +int i2c_probe(u8 dev) +{ + /* Attempt to read a byte */ + setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO | + ZYNQ_I2C_CONTROL_RW); + clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD); + writel(0xFF, &zynq_i2c->interrupt_status); + writel(dev, &zynq_i2c->address); + writel(1, &zynq_i2c->transfer_size); + + return (zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP | + ZYNQ_I2C_INTERRUPT_NACK) & + ZYNQ_I2C_INTERRUPT_COMP) ? 0 : -ETIMEDOUT; +} + +/* + * I2C read called by cmd_i2c when doing 'i2c read' and by cmd_eeprom.c + * Begin write, send address byte(s), begin read, receive data bytes, end. + */ +int i2c_read(u8 dev, uint addr, int alen, u8 *data, int length) +{ + u32 status; + u32 i = 0; + u8 *cur_data = data; + + /* Check the hardware can handle the requested bytes */ + if ((length < 0) || (length > ZYNQ_I2C_TRANSFERT_SIZE_MAX)) + return -EINVAL; + + /* Write the register address */ + setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO | + ZYNQ_I2C_CONTROL_HOLD); + /* + * Temporarily disable restart (by clearing hold) + * It doesn't seem to work. + */ + clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_RW | + ZYNQ_I2C_CONTROL_HOLD); + writel(0xFF, &zynq_i2c->interrupt_status); + while (alen--) + writel(addr >> (8*alen), &zynq_i2c->data); + writel(dev, &zynq_i2c->address); + + /* Wait for the address to be sent */ + if (!zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP)) { + /* Release the bus */ + clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD); + return -ETIMEDOUT; + } + debug("Device acked address\n"); + + setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO | + ZYNQ_I2C_CONTROL_RW); + /* Start reading data */ + writel(dev, &zynq_i2c->address); + writel(length, &zynq_i2c->transfer_size); + + /* Wait for data */ + do { + status = zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP | + ZYNQ_I2C_INTERRUPT_DATA); + if (!status) { + /* Release the bus */ + clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD); + return -ETIMEDOUT; + } + debug("Read %d bytes\n", + length - readl(&zynq_i2c->transfer_size)); + for (; i < length - readl(&zynq_i2c->transfer_size); i++) + *(cur_data++) = readl(&zynq_i2c->data); + } while (readl(&zynq_i2c->transfer_size) != 0); + /* All done... release the bus */ + clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD); + +#ifdef DEBUG + zynq_i2c_debug_status(); +#endif + return 0; +} + +/* + * I2C write called by cmd_i2c when doing 'i2c write' and by cmd_eeprom.c + * Begin write, send address byte(s), send data bytes, end. + */ +int i2c_write(u8 dev, uint addr, int alen, u8 *data, int length) +{ + u8 *cur_data = data; + + /* Write the register address */ + setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO | + ZYNQ_I2C_CONTROL_HOLD); + clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_RW); + writel(0xFF, &zynq_i2c->interrupt_status); + while (alen--) + writel(addr >> (8*alen), &zynq_i2c->data); + /* Start the tranfer */ + writel(dev, &zynq_i2c->address); + if (!zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP)) { + /* Release the bus */ + clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD); + return -ETIMEDOUT; + } + + debug("Device acked address\n"); + while (length--) { + writel(*(cur_data++), &zynq_i2c->data); + if (readl(&zynq_i2c->transfer_size) == ZYNQ_I2C_FIFO_DEPTH) { + if (!zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP)) { + /* Release the bus */ + clrbits_le32(&zynq_i2c->control, + ZYNQ_I2C_CONTROL_HOLD); + return -ETIMEDOUT; + } + } + } + + /* All done... release the bus */ + clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD); + /* Wait for the address and data to be sent */ + if (!zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP)) + return -ETIMEDOUT; + return 0; +} + +int i2c_set_bus_num(unsigned int bus) +{ + /* Only support bus 0 */ + if (bus > 0) + return -1; + return 0; +} + +unsigned int i2c_get_bus_num(void) +{ + /* Only support bus 0 */ + return 0; +} diff --git a/include/configs/zynq.h b/include/configs/zynq.h index 2ed88a7..f1f182e 100644 --- a/include/configs/zynq.h +++ b/include/configs/zynq.h @@ -72,6 +72,17 @@ # define CONFIG_DOS_PARTITION #endif
+#define CONFIG_ZYNQ_I2C0 + +/* I2C */ +#if defined(CONFIG_ZYNQ_I2C0) || defined(CONFIG_ZYNQ_I2C1) +# define CONFIG_CMD_I2C +# define CONFIG_ZYNQ_I2C +# define CONFIG_HARD_I2C +# define CONFIG_SYS_I2C_SPEED 100000 +# define CONFIG_SYS_I2C_SLAVE 1 +#endif + #if defined(CONFIG_ZYNQ_DCC) # define CONFIG_ARM_DCC # define CONFIG_CPU_V6 /* Required by CONFIG_ARM_DCC */ -- 1.8.2.1

Hello Michal,
AOn 23.04.2013 12:46, Michal Simek wrote:
Support Xilinx Zynq i2c controller.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Signed-off-by: Michal Simek michal.simek@xilinx.com CC: Heiko Schocher hs@denx.de
Changes in v2:
- Remove CONFIG_ prefix from non configurable macros (i2c)
- Fix checkpatch warnings (i2c)
- Fix #define<space>Macro name (i2c)
- Fix multiline comments (i2c)
- Remove trailing 1 for configurations (i2c)
arch/arm/include/asm/arch-zynq/hardware.h | 2 + drivers/i2c/Makefile | 1 + drivers/i2c/zynq_i2c.c | 306 ++++++++++++++++++++++++++++++ include/configs/zynq.h | 11 ++ 4 files changed, 320 insertions(+) create mode 100644 drivers/i2c/zynq_i2c.c
As this is in a patchserie, I just ack your patch:
Ackd-by: Heiko Schocher hs@denx.de
Thanks!
bye, Heiko

On 04/29/2013 05:39 AM, Heiko Schocher wrote:
Hello Michal,
AOn 23.04.2013 12:46, Michal Simek wrote:
Support Xilinx Zynq i2c controller.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Signed-off-by: Michal Simek michal.simek@xilinx.com CC: Heiko Schocher hs@denx.de
Changes in v2:
- Remove CONFIG_ prefix from non configurable macros (i2c)
- Fix checkpatch warnings (i2c)
- Fix #define<space>Macro name (i2c)
- Fix multiline comments (i2c)
- Remove trailing 1 for configurations (i2c)
arch/arm/include/asm/arch-zynq/hardware.h | 2 + drivers/i2c/Makefile | 1 + drivers/i2c/zynq_i2c.c | 306 ++++++++++++++++++++++++++++++ include/configs/zynq.h | 11 ++ 4 files changed, 320 insertions(+) create mode 100644 drivers/i2c/zynq_i2c.c
As this is in a patchserie, I just ack your patch:
Ackd-by: Heiko Schocher hs@denx.de
Thanks, Michal

Devcfg device requires to load bitstream in binary format.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com Signed-off-by: Michal Simek michal.simek@xilinx.com --- Changes in v2: - Fix bugs reported by Tom Rini - Fix checkpatch warnings (fpga) - Fix comments (fpga) - Do not use CamelCase for XilinxZynq (fpga)
arch/arm/cpu/armv7/zynq/slcr.c | 35 +++++ arch/arm/include/asm/arch-zynq/hardware.h | 10 +- arch/arm/include/asm/arch-zynq/sys_proto.h | 3 + board/xilinx/zynq/board.c | 37 +++++ drivers/fpga/Makefile | 1 + drivers/fpga/xilinx.c | 37 +++++ drivers/fpga/zynqpl.c | 231 +++++++++++++++++++++++++++++ include/configs/zynq.h | 6 + include/xilinx.h | 4 + include/zynqpl.h | 59 ++++++++ 10 files changed, 421 insertions(+), 2 deletions(-) create mode 100644 drivers/fpga/zynqpl.c create mode 100644 include/zynqpl.h
diff --git a/arch/arm/cpu/armv7/zynq/slcr.c b/arch/arm/cpu/armv7/zynq/slcr.c index 5a8674a..52048c6 100644 --- a/arch/arm/cpu/armv7/zynq/slcr.c +++ b/arch/arm/cpu/armv7/zynq/slcr.c @@ -28,6 +28,9 @@ #define SLCR_LOCK_MAGIC 0x767B #define SLCR_UNLOCK_MAGIC 0xDF0D
+#define SLCR_IDCODE_MASK 0x1F000 +#define SLCR_IDCODE_SHIFT 12 + static int slcr_lock = 1; /* 1 means locked, 0 means unlocked */
void zynq_slcr_lock(void) @@ -87,3 +90,35 @@ void zynq_slcr_gem_clk_setup(u32 gem_id, u32 rclk, u32 clk) out: zynq_slcr_lock(); } + +void zynq_slcr_devcfg_disable(void) +{ + zynq_slcr_unlock(); + + /* Disable AXI interface */ + writel(0xFFFFFFFF, &slcr_base->fpga_rst_ctrl); + + /* Set Level Shifters DT618760 */ + writel(0xA, &slcr_base->lvl_shftr_en); + + zynq_slcr_lock(); +} + +void zynq_slcr_devcfg_enable(void) +{ + zynq_slcr_unlock(); + + /* Set Level Shifters DT618760 */ + writel(0xF, &slcr_base->lvl_shftr_en); + + /* Disable AXI interface */ + writel(0x0, &slcr_base->fpga_rst_ctrl); + + zynq_slcr_lock(); +} + +u32 zynq_slcr_get_idcode(void) +{ + return (readl(&slcr_base->pss_idcode) & SLCR_IDCODE_MASK) >> + SLCR_IDCODE_SHIFT; +} diff --git a/arch/arm/include/asm/arch-zynq/hardware.h b/arch/arm/include/asm/arch-zynq/hardware.h index 6af892a..8b8a91a 100644 --- a/arch/arm/include/asm/arch-zynq/hardware.h +++ b/arch/arm/include/asm/arch-zynq/hardware.h @@ -53,11 +53,17 @@ struct slcr_regs { u32 boot_mode; /* 0x25c */ u32 reserved4[116]; u32 trust_zone; /* 0x430 */ /* FIXME */ - u32 reserved5[115]; + u32 reserved5_1[63]; + u32 pss_idcode; /* 0x530 */ + u32 reserved5_2[51]; u32 ddr_urgent; /* 0x600 */ u32 reserved6[6]; u32 ddr_urgent_sel; /* 0x61c */ - u32 reserved7[188]; + u32 reserved7[56]; + u32 mio_pin[54]; /* 0x700 - 0x7D4 */ + u32 reserved8[74]; + u32 lvl_shftr_en; /* 0x900 */ + u32 reserved9[3]; u32 ocm_cfg; /* 0x910 */ };
diff --git a/arch/arm/include/asm/arch-zynq/sys_proto.h b/arch/arm/include/asm/arch-zynq/sys_proto.h index af9e7f8..2317121 100644 --- a/arch/arm/include/asm/arch-zynq/sys_proto.h +++ b/arch/arm/include/asm/arch-zynq/sys_proto.h @@ -27,6 +27,9 @@ extern void zynq_slcr_lock(void); extern void zynq_slcr_unlock(void); extern void zynq_slcr_cpu_reset(void); extern void zynq_slcr_gem_clk_setup(u32 gem_id, u32 rclk, u32 clk); +extern void zynq_slcr_devcfg_disable(void); +extern void zynq_slcr_devcfg_enable(void); +extern u32 zynq_slcr_get_idcode(void);
/* Driver extern functions */ extern int zynq_sdhci_init(u32 regbase); diff --git a/board/xilinx/zynq/board.c b/board/xilinx/zynq/board.c index 1589d21..b02c364 100644 --- a/board/xilinx/zynq/board.c +++ b/board/xilinx/zynq/board.c @@ -22,15 +22,52 @@
#include <common.h> #include <netdev.h> +#include <zynqpl.h> #include <asm/arch/hardware.h> #include <asm/arch/sys_proto.h>
DECLARE_GLOBAL_DATA_PTR;
+#ifdef CONFIG_FPGA +Xilinx_desc fpga; + +/* It can be done differently */ +Xilinx_desc fpga010 = XILINX_XC7Z010_DESC(0x10); +Xilinx_desc fpga020 = XILINX_XC7Z020_DESC(0x20); +Xilinx_desc fpga030 = XILINX_XC7Z030_DESC(0x30); +Xilinx_desc fpga045 = XILINX_XC7Z045_DESC(0x45); +#endif + int board_init(void) { +#ifdef CONFIG_FPGA + u32 idcode; + + idcode = zynq_slcr_get_idcode(); + + switch (idcode) { + case XILINX_ZYNQ_7010: + fpga = fpga010; + break; + case XILINX_ZYNQ_7020: + fpga = fpga020; + break; + case XILINX_ZYNQ_7030: + fpga = fpga030; + break; + case XILINX_ZYNQ_7045: + fpga = fpga045; + break; + } +#endif + icache_enable();
+#ifdef CONFIG_FPGA + fpga_init(); + fpga_add(fpga_xilinx, &fpga); +#endif + return 0; }
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index b48f623..0b51dcd 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -30,6 +30,7 @@ COBJS-y += fpga.o COBJS-$(CONFIG_FPGA_SPARTAN2) += spartan2.o COBJS-$(CONFIG_FPGA_SPARTAN3) += spartan3.o COBJS-$(CONFIG_FPGA_VIRTEX2) += virtex2.o +COBJS-$(CONFIG_FPGA_ZYNQPL) += zynqpl.o COBJS-$(CONFIG_FPGA_XILINX) += xilinx.o COBJS-$(CONFIG_FPGA_LATTICE) += ivm_core.o lattice.o ifdef CONFIG_FPGA_ALTERA diff --git a/drivers/fpga/xilinx.c b/drivers/fpga/xilinx.c index 32787b2..fe324ab 100644 --- a/drivers/fpga/xilinx.c +++ b/drivers/fpga/xilinx.c @@ -1,4 +1,6 @@ /* + * (C) Copyright 2012-2013, Xilinx, Michal Simek + * * (C) Copyright 2002 * Rich Ireland, Enterasys Networks, rireland@enterasys.com. * Keith Outwater, keith_outwater@mvis.com @@ -31,6 +33,7 @@ #include <virtex2.h> #include <spartan2.h> #include <spartan3.h> +#include <zynqpl.h>
#if 0 #define FPGA_DEBUG @@ -86,6 +89,16 @@ int xilinx_load(Xilinx_desc *desc, const void *buf, size_t bsize) __FUNCTION__); #endif break; + case xilinx_zynq: +#if defined(CONFIG_FPGA_ZYNQPL) + PRINTF("%s: Launching the Zynq PL Loader...\n", + __func__); + ret_val = zynq_load(desc, buf, bsize); +#else + printf("%s: No support for Zynq devices.\n", + __func__); +#endif + break;
default: printf ("%s: Unsupported family type, %d\n", @@ -133,6 +146,16 @@ int xilinx_dump(Xilinx_desc *desc, const void *buf, size_t bsize) __FUNCTION__); #endif break; + case xilinx_zynq: +#if defined(CONFIG_FPGA_ZYNQPL) + PRINTF("%s: Launching the Zynq PL Reader...\n", + __func__); + ret_val = zynq_dump(desc, buf, bsize); +#else + printf("%s: No support for Zynq devices.\n", + __func__); +#endif + break;
default: printf ("%s: Unsupported family type, %d\n", @@ -158,6 +181,9 @@ int xilinx_info (Xilinx_desc * desc) case Xilinx_Virtex2: printf ("Virtex-II\n"); break; + case xilinx_zynq: + printf("Zynq PL\n"); + break; /* Add new family types here */ default: printf ("Unknown family type, %d\n", desc->family); @@ -183,6 +209,9 @@ int xilinx_info (Xilinx_desc * desc) case master_selectmap: printf ("Master SelectMap Mode\n"); break; + case devcfg: + printf("Device configuration interface (Zynq)\n"); + break; /* Add new interface types here */ default: printf ("Unsupported interface type, %d\n", desc->iface); @@ -222,6 +251,14 @@ int xilinx_info (Xilinx_desc * desc) __FUNCTION__); #endif break; + case xilinx_zynq: +#if defined(CONFIG_FPGA_ZYNQPL) + zynq_info(desc); +#else + /* just in case */ + printf("%s: No support for Zynq devices.\n", + __func__); +#endif /* Add new family types here */ default: /* we don't need a message here - we give one up above */ diff --git a/drivers/fpga/zynqpl.c b/drivers/fpga/zynqpl.c new file mode 100644 index 0000000..0365803 --- /dev/null +++ b/drivers/fpga/zynqpl.c @@ -0,0 +1,231 @@ +/* + * (C) Copyright 2012-2013, Xilinx, Michal Simek + * + * (C) Copyright 2012 + * Joe Hershberger joe.hershberger@ni.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/io.h> +#include <zynqpl.h> +#include <asm/arch/hardware.h> +#include <asm/arch/sys_proto.h> + +#define DEVCFG_CTRL_PCFG_PROG_B 0x40000000 +#define DEVCFG_ISR_FATAL_ERROR_MASK 0x00740040 +#define DEVCFG_ISR_ERROR_FLAGS_MASK 0x00340840 +#define DEVCFG_ISR_RX_FIFO_OV 0x00040000 +#define DEVCFG_ISR_DMA_DONE 0x00002000 +#define DEVCFG_ISR_PCFG_DONE 0x00000004 +#define DEVCFG_STATUS_DMA_CMD_Q_F 0x80000000 +#define DEVCFG_STATUS_DMA_CMD_Q_E 0x40000000 +#define DEVCFG_STATUS_DMA_DONE_CNT_MASK 0x30000000 +#define DEVCFG_STATUS_PCFG_INIT 0x00000010 +#define DEVCFG_MCTRL_RFIFO_FLUSH 0x00000002 +#define DEVCFG_MCTRL_WFIFO_FLUSH 0x00000001 + +#ifndef CONFIG_SYS_FPGA_WAIT +#define CONFIG_SYS_FPGA_WAIT CONFIG_SYS_HZ/100 /* 10 ms */ +#endif + +#ifndef CONFIG_SYS_FPGA_PROG_TIME +#define CONFIG_SYS_FPGA_PROG_TIME CONFIG_SYS_HZ /* 1 s */ +#endif + +int zynq_info(Xilinx_desc *desc) +{ + return FPGA_SUCCESS; +} + +/* Xilinx binary format header */ +static const u32 bin_format[] = { + 0xffffffff, /* Dummy words */ + 0xffffffff, + 0xffffffff, + 0xffffffff, + 0xffffffff, + 0xffffffff, + 0xffffffff, + 0xffffffff, + 0x000000bb, /* Sync word */ + 0x11220044, /* Sync word */ + 0xffffffff, + 0xffffffff, + 0xaa995566, /* Sync word */ +}; + +int zynq_load(Xilinx_desc *desc, const void *buf, size_t bsize) +{ + unsigned long ts; /* Timestamp */ + u32 control; + u32 isr_status; + u32 status; + const u32 *test = buf; + int i; + + if ((u32)buf & 0x3) { + printf("Error: Buffer is not aligned %x\n", (u32)buf); + return FPGA_FAIL; + } + + /* Check bitstream size */ + if (bsize != desc->size) { + printf("Error: File size is wrong - should be %x.\n", + desc->size); + return FPGA_FAIL; + } + + /* Checking that passing bin is not a bitstream */ + for (i = 0; i < ARRAY_SIZE(bin_format); i++) { + if (test[i] != bin_format[i]) { + puts("Error: File not in binary format.\n"); + return FPGA_FAIL; + } + } + + zynq_slcr_devcfg_disable(); + + /* Setting PCFG_PROG_B signal to high */ + control = readl(&devcfg_base->ctrl); + writel(control | DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl); + /* Setting PCFG_PROG_B signal to low */ + writel(control & ~DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl); + + /* Polling the PCAP_INIT status for Reset */ + ts = get_timer(0); + while (readl(&devcfg_base->status) & DEVCFG_STATUS_PCFG_INIT) { + if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) { + puts("Error: Timeout waiting for INIT to clear.\n"); + return FPGA_FAIL; + } + } + + /* Setting PCFG_PROG_B signal to high */ + writel(control | DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl); + + /* Polling the PCAP_INIT status for Set */ + ts = get_timer(0); + while (!(readl(&devcfg_base->status) & DEVCFG_STATUS_PCFG_INIT)) { + if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) { + puts("Error: Timeout waiting for INIT to set.\n"); + return FPGA_FAIL; + } + } + + isr_status = readl(&devcfg_base->int_sts); + + /* Clear it all, so if Boot ROM comes back, it can proceed */ + writel(0xFFFFFFFF, &devcfg_base->int_sts); + + if (isr_status & DEVCFG_ISR_FATAL_ERROR_MASK) { + debug("Fatal errors in PCAP 0x%X\n", isr_status); + + /* If RX FIFO overflow, need to flush RX FIFO first */ + if (isr_status & DEVCFG_ISR_RX_FIFO_OV) { + writel(DEVCFG_MCTRL_RFIFO_FLUSH, &devcfg_base->mctrl); + writel(0xFFFFFFFF, &devcfg_base->int_sts); + } + return FPGA_FAIL; + } + + status = readl(&devcfg_base->status); + + debug("status = 0x%08X\n", status); + + if (status & DEVCFG_STATUS_DMA_CMD_Q_F) { + debug("Error: device busy\n"); + return FPGA_FAIL; + } + + debug("device ready\n"); + + if (!(status & DEVCFG_STATUS_DMA_CMD_Q_E)) { + if (!(readl(&devcfg_base->int_sts) & DEVCFG_ISR_DMA_DONE)) { + /* Error state, transfer cannot occur */ + debug("isr indicates error\n"); + return FPGA_FAIL; + } else { + /* Clear out the status */ + writel(DEVCFG_ISR_DMA_DONE, &devcfg_base->int_sts); + } + } + + if (status & DEVCFG_STATUS_DMA_DONE_CNT_MASK) { + /* Clear the count of completed DMA transfers */ + writel(DEVCFG_STATUS_DMA_DONE_CNT_MASK, &devcfg_base->status); + } + + debug("Source = 0x%08X\n", (u32)buf); + debug("Size = %zu\n", bsize); + + /* Set up the transfer */ + writel((u32)buf | 1, &devcfg_base->dma_src_addr); + writel(0xFFFFFFFF, &devcfg_base->dma_dst_addr); + writel(bsize >> 2, &devcfg_base->dma_src_len); + writel(0, &devcfg_base->dma_dst_len); + + isr_status = readl(&devcfg_base->int_sts); + + /* Polling the PCAP_INIT status for Set */ + ts = get_timer(0); + while (!(isr_status & DEVCFG_ISR_DMA_DONE)) { + if (isr_status & DEVCFG_ISR_ERROR_FLAGS_MASK) { + debug("Error: isr = 0x%08X\n", isr_status); + debug("Write count = 0x%08X\n", + readl(&devcfg_base->write_count)); + debug("Read count = 0x%08X\n", + readl(&devcfg_base->read_count)); + + return FPGA_FAIL; + } + if (get_timer(ts) > CONFIG_SYS_FPGA_PROG_TIME) { + puts("Error: Timeout waiting for DMA to complete.\n"); + return FPGA_FAIL; + } + isr_status = readl(&devcfg_base->int_sts); + } + + debug("DMA transfer is done\n"); + + /* Check FPGA configuration completion */ + ts = get_timer(0); + while (!(isr_status & DEVCFG_ISR_PCFG_DONE)) { + if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) { + puts("Error: Timeout waiting for FPGA to config.\n"); + return FPGA_FAIL; + } + isr_status = readl(&devcfg_base->int_sts); + } + + debug("FPGA config done\n"); + + /* Clear out the DMA status */ + writel(DEVCFG_ISR_DMA_DONE, &devcfg_base->int_sts); + + zynq_slcr_devcfg_enable(); + + return FPGA_SUCCESS; +} + +int zynq_dump(Xilinx_desc *desc, const void *buf, size_t bsize) +{ + return FPGA_FAIL; +} diff --git a/include/configs/zynq.h b/include/configs/zynq.h index f1f182e..38f04f6 100644 --- a/include/configs/zynq.h +++ b/include/configs/zynq.h @@ -88,6 +88,12 @@ # define CONFIG_CPU_V6 /* Required by CONFIG_ARM_DCC */ #endif
+/* Enable the PL to be downloaded */ +#define CONFIG_FPGA +#define CONFIG_FPGA_XILINX +#define CONFIG_FPGA_ZYNQPL +#define CONFIG_CMD_FPGA + #define CONFIG_BOOTP_SERVERIP #define CONFIG_BOOTP_BOOTPATH #define CONFIG_BOOTP_GATEWAY diff --git a/include/xilinx.h b/include/xilinx.h index 5f25b7a..592cbea 100644 --- a/include/xilinx.h +++ b/include/xilinx.h @@ -33,10 +33,12 @@ #define CONFIG_SYS_VIRTEX_E CONFIG_SYS_FPGA_DEV( 0x2 ) #define CONFIG_SYS_VIRTEX2 CONFIG_SYS_FPGA_DEV( 0x4 ) #define CONFIG_SYS_SPARTAN3 CONFIG_SYS_FPGA_DEV( 0x8 ) +#define CONFIG_SYS_ZYNQ CONFIG_SYS_FPGA_DEV(0x10) #define CONFIG_SYS_XILINX_SPARTAN2 (CONFIG_SYS_FPGA_XILINX | CONFIG_SYS_SPARTAN2) #define CONFIG_SYS_XILINX_VIRTEX_E (CONFIG_SYS_FPGA_XILINX | CONFIG_SYS_VIRTEX_E) #define CONFIG_SYS_XILINX_VIRTEX2 (CONFIG_SYS_FPGA_XILINX | CONFIG_SYS_VIRTEX2) #define CONFIG_SYS_XILINX_SPARTAN3 (CONFIG_SYS_FPGA_XILINX | CONFIG_SYS_SPARTAN3) +#define CONFIG_SYS_XILINX_ZYNQ (CONFIG_SYS_FPGA_XILINX | CONFIG_SYS_ZYNQ) /* XXX - Add new models here */
@@ -59,6 +61,7 @@ typedef enum { /* typedef Xilinx_iface */ jtag_mode, /* jtag/tap serial (not used ) */ master_selectmap, /* master SelectMap (virtex2) */ slave_selectmap, /* slave SelectMap (virtex2) */ + devcfg, /* devcfg interface (zynq) */ max_xilinx_iface_type /* insert all new types before this */ } Xilinx_iface; /* end, typedef Xilinx_iface */
@@ -68,6 +71,7 @@ typedef enum { /* typedef Xilinx_Family */ Xilinx_VirtexE, /* Virtex-E Family */ Xilinx_Virtex2, /* Virtex2 Family */ Xilinx_Spartan3, /* Spartan-III Family */ + xilinx_zynq, /* Zynq Family */ max_xilinx_type /* insert all new types before this */ } Xilinx_Family; /* end, typedef Xilinx_Family */
diff --git a/include/zynqpl.h b/include/zynqpl.h new file mode 100644 index 0000000..bc9b948 --- /dev/null +++ b/include/zynqpl.h @@ -0,0 +1,59 @@ +/* + * (C) Copyright 2012-2013, Xilinx, Michal Simek + * + * (C) Copyright 2012 + * Joe Hershberger joe.hershberger@ni.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _ZYNQPL_H_ +#define _ZYNQPL_H_ + +#include <xilinx.h> + +extern int zynq_load(Xilinx_desc *desc, const void *image, size_t size); +extern int zynq_dump(Xilinx_desc *desc, const void *buf, size_t bsize); +extern int zynq_info(Xilinx_desc *desc); + +#define XILINX_ZYNQ_7010 0x2 +#define XILINX_ZYNQ_7020 0x7 +#define XILINX_ZYNQ_7030 0xc +#define XILINX_ZYNQ_7045 0x11 + +/* Device Image Sizes */ +#define XILINX_XC7Z010_SIZE 16669920/8 +#define XILINX_XC7Z020_SIZE 32364512/8 +#define XILINX_XC7Z030_SIZE 47839328/8 +#define XILINX_XC7Z045_SIZE 106571232/8 + +/* Descriptor Macros */ +#define XILINX_XC7Z010_DESC(cookie) \ +{ xilinx_zynq, devcfg, XILINX_XC7Z010_SIZE, NULL, cookie } + +#define XILINX_XC7Z020_DESC(cookie) \ +{ xilinx_zynq, devcfg, XILINX_XC7Z020_SIZE, NULL, cookie } + +#define XILINX_XC7Z030_DESC(cookie) \ +{ xilinx_zynq, devcfg, XILINX_XC7Z030_SIZE, NULL, cookie } + +#define XILINX_XC7Z045_DESC(cookie) \ +{ xilinx_zynq, devcfg, XILINX_XC7Z045_SIZE, NULL, cookie } + +#endif /* _ZYNQPL_H_ */ -- 1.8.2.1

On Tue, Apr 23, 2013 at 12:45:59PM +0200, Michal Simek wrote:
Patchset contains several patches which improve Xilinx Zynq arm port. Patchset contain:
- core changes
- gem updates
- mmc support
- i2c support
- pl support
I am sending them in one package because driver depends on each other in zynq shared files.
Thanks for your comments, Michal
P.S.: The first version sent by patman that's why sorry for any mistake.
Changes in v2:
- New patch in this series to reflect Tom's comments
- Remove XPSS_ prefix and replace it with ZYNQ
- Remove CONFIG_ prefix from non configurable macros (scutimer)
- Remove CONFIG_ prefix from non configurable macro (gem)
- Remove CONFIG_ prefix from non configurable macros (emio)
- Remove CONFIG_ prefix from non configurable macros (sdhci)
- Remove CONFIG_ prefix from non configurable macros (i2c)
- Fix checkpatch warnings (i2c)
- Fix #define<space>Macro name (i2c)
- Fix multiline comments (i2c)
- Remove trailing 1 for configurations (i2c)
- Fix bugs reported by Tom Rini
- Fix checkpatch warnings (fpga)
- Fix comments (fpga)
- Do not use CamelCase for XilinxZynq (fpga)
David Andrey (3): arm: zynq: U-Boot udelay < 1000 FIX net: gem: Pass phy address to init net: gem: Preserve clk on emio interface
Michal Simek (12): arm: zynq: Rename XPSS_ prefix to ZYNQ_ for hardcoded SoC addresses zynq: Move scutimer baseaddr to hardware.h net: phy: Define Marvell 88e1518 phy net: gem: Remove WRAP bit from TX buffer description net: gem: Simplify return path in zynq_gem_recv net: gem: Do not initialize BDs again net: gem: Fix gem driver on 1Gbps LAN zynq: Move macros to hardware.h net: gem: Add support for phy autodetection mmc: Add support for Xilinx Zynq sdhci controller i2c: zynq: Add support for Xilinx Zynq fpga: Add support for loading bitstream for Xilinx Zynq
arch/arm/cpu/armv7/zynq/slcr.c | 61 ++++++ arch/arm/cpu/armv7/zynq/timer.c | 49 ++++- arch/arm/include/asm/arch-zynq/hardware.h | 36 +++- arch/arm/include/asm/arch-zynq/sys_proto.h | 7 + board/xilinx/zynq/board.c | 66 ++++++- drivers/fpga/Makefile | 1 + drivers/fpga/xilinx.c | 37 ++++ drivers/fpga/zynqpl.c | 231 ++++++++++++++++++++++ drivers/i2c/Makefile | 1 + drivers/i2c/zynq_i2c.c | 306 +++++++++++++++++++++++++++++ drivers/mmc/Makefile | 1 + drivers/mmc/zynq_sdhci.c | 40 ++++ drivers/net/phy/marvell.c | 11 ++ drivers/net/zynq_gem.c | 199 +++++++++++++------ include/configs/zynq.h | 39 +++- include/netdev.h | 2 +- include/xilinx.h | 4 + include/zynqpl.h | 59 ++++++ 18 files changed, 1065 insertions(+), 85 deletions(-) create mode 100644 drivers/fpga/zynqpl.c create mode 100644 drivers/i2c/zynq_i2c.c create mode 100644 drivers/mmc/zynq_sdhci.c create mode 100644 include/zynqpl.h
For the series: Reviewed-by: Tom Rini trini@ti.com
participants (4)
-
Heiko Schocher
-
Michal Simek
-
Michal Simek
-
Tom Rini