From owner-freebsd-arm@FreeBSD.ORG Tue Jun 24 19:46:54 2014 Return-Path: Delivered-To: freebsd-arm@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id D98D6AE7 for ; Tue, 24 Jun 2014 19:46:54 +0000 (UTC) Received: from nm27-vm5.access.bullet.mail.bf1.yahoo.com (nm27-vm5.access.bullet.mail.bf1.yahoo.com [216.109.115.228]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 7881824F8 for ; Tue, 24 Jun 2014 19:46:53 +0000 (UTC) Received: from [66.196.81.162] by nm27.access.bullet.mail.bf1.yahoo.com with NNFMP; 24 Jun 2014 19:44:17 -0000 Received: from [98.138.226.243] by tm8.access.bullet.mail.bf1.yahoo.com with NNFMP; 24 Jun 2014 19:44:17 -0000 Received: from [127.0.0.1] by smtp114.sbc.mail.ne1.yahoo.com with NNFMP; 24 Jun 2014 19:44:17 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sbcglobal.net; s=s1024; t=1403639057; bh=WeUZOpDnK/sfD+J3vn7qL9jjzRy9HxzpqxWhHY5Cosk=; h=X-Yahoo-Newman-Id:X-Yahoo-Newman-Property:X-YMail-OSG:X-Yahoo-SMTP:X-Rocket-Received:Message-ID:Date:From:User-Agent:MIME-Version:To:Subject:Content-Type; b=kOdZg0cbqqEKIlpcG1IuAPkKvEb4QbszCPM3Em4t3L/0HdjgyCHiLvlk2IvCXM6fdqgv2THWHcZJqOVrKs9idlxw3gRMZ/XgO+UZ1j0dh8XYf8VPhypLirl303w1dK4UU/9w4+TYRFlepJhzYjhjxvYb/huRTOgxajSDtkpKpo8= X-Yahoo-Newman-Id: 118473.12067.bm@smtp114.sbc.mail.ne1.yahoo.com X-Yahoo-Newman-Property: ymail-3 X-YMail-OSG: tFiaCTkVM1mrZjmYWOV6bLOSNxAzJ64Aq9Mw0KdojcY_h0l cTTdXlvUaUtYce2QFLfmOxR76duDGI1bfTUQggKeD0JLz4n8M6F.ZkutZp8x 2BZQ9CmhwuQAKL7vteh4N5O8WGgBzryXdUlGcPOHMCdctb7Fuu.NkVVAjxF2 K.IhLAFLXHR11.1IZerXazNyfLrH2CyEb5eO_GzBD3Mm7O7u1hvmY43WBi51 GJsxh5d7k0.q4iP7fcrgFvRMFxMOd5swiRx7Fs_C5yJU9BGOSQoKH1QpTM8E 3aikUEhdgUchEck7Ci2QbJWpY_DnUM6wd7fLBfzGhANXdjpEopkU_uIPp6co s86slaBBgJuqOazb0v33Ap1EW35_.R30pbep5dne778SQtjnroYbczRpABlD AZBjU23clN2XQeaLNmc5Djv.ctZc05vcyqqOZcrparUuer9AfiqB_uwx1Y.C z4XBvXfyvJW6uk6z5ujPgVupCwQXv8hEUL1oyntp8cxjKPeOBlpr7gX7vzsy BcUFAnWnuCZDWUwZMvQEj1KnUt519tAZr.eZzjFGpIYOCq6lEEOkpqTf1 X-Yahoo-SMTP: tUxoRneswBA21azLM.3ybMESf0mC2bFhTbmt0VU5ervH0kqi5lo- X-Rocket-Received: from [192.168.1.9] (ThomasSkibo@71.139.167.11 with plain [98.138.31.74]) by smtp114.sbc.mail.ne1.yahoo.com with SMTP; 24 Jun 2014 19:44:17 +0000 UTC Message-ID: <53A9D50F.8030604@sbcglobal.net> Date: Tue, 24 Jun 2014 12:44:15 -0700 From: Thomas Skibo User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:24.0) Gecko/20100101 Thunderbird/24.6.0 MIME-Version: 1.0 To: freebsd-arm Subject: Some bug fixes for Zynq Ethernet Content-Type: multipart/mixed; boundary="------------030800060005090008020207" X-BeenThere: freebsd-arm@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: "Porting FreeBSD to ARM processors." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Jun 2014 19:46:54 -0000 This is a multi-part message in MIME format. --------------030800060005090008020207 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Hello, all. I have some bug fixes for the Zynq/Zedboard Ethernet driver that have been laying around for a while and that I'm hoping to get committed. The main bug is that the driver doesn't handle media speed changes correctly so it can only connect to 1G switches. To fix this bug, the driver needs to be able to change the frequency of the ethernet core's reference clock. Because I am trying to keep if_cgem.c platform-independent, I've created a function called cgem_set_ref_clk() that a platform can override with a platform-specific function for changing the clock. This should make it easier if the Cadence GEM block shows up in other SoCs. Where it is a bit ugly is that the driver doesn't know which of two ethernet cores it controls so I created a device-tree property called "ref-clock-num" so that the platform-specific code knows which reference clock to change. I am open to other ideas on how to do this. Comments? I have a few other minor fixes and enhancements that I'll put in a different patch. Thanks, -- -------- Thomas Skibo ThomasSkibo@sbcglobal.net --------------030800060005090008020207 Content-Type: text/plain; charset=UTF-8; name="patch.media-bug.txt" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="patch.media-bug.txt" Index: sys/arm/xilinx/zy7_slcr.c =================================================================== --- sys/arm/xilinx/zy7_slcr.c (revision 267546) +++ sys/arm/xilinx/zy7_slcr.c (working copy) @@ -71,20 +71,22 @@ #define ZSLCR_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) #define ZSLCR_LOCK_INIT(sc) \ mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), \ - "zy7_slcr", MTX_SPIN) + "zy7_slcr", MTX_DEF) #define ZSLCR_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); #define RD4(sc, off) (bus_read_4((sc)->mem_res, (off))) #define WR4(sc, off, val) (bus_write_4((sc)->mem_res, (off), (val))) +#define ZYNQ_DEFAULT_PS_CLK_FREQUENCY 33333333 /* 33.3 Mhz */ + SYSCTL_NODE(_hw, OID_AUTO, zynq, CTLFLAG_RD, 0, "Xilinx Zynq-7000"); static char zynq_bootmode[64]; SYSCTL_STRING(_hw_zynq, OID_AUTO, bootmode, CTLFLAG_RD, zynq_bootmode, 0, "Zynq boot mode"); -static char zynq_pssid[80]; +static char zynq_pssid[100]; SYSCTL_STRING(_hw_zynq, OID_AUTO, pssid, CTLFLAG_RD, zynq_pssid, 0, "Zynq PSS IDCODE"); @@ -92,6 +94,22 @@ SYSCTL_INT(_hw_zynq, OID_AUTO, reboot_status, CTLFLAG_RD, &zynq_reboot_status, 0, "Zynq REBOOT_STATUS register"); +static int ps_clk_frequency; +SYSCTL_INT(_hw_zynq, OID_AUTO, ps_clk_frequency, CTLFLAG_RD, &ps_clk_frequency, + 0, "Zynq PS_CLK Frequency"); + +static int io_pll_frequency; +SYSCTL_INT(_hw_zynq, OID_AUTO, io_pll_frequency, CTLFLAG_RD, &io_pll_frequency, + 0, "Zynq IO PLL Frequency"); + +static int arm_pll_frequency; +SYSCTL_INT(_hw_zynq, OID_AUTO, arm_pll_frequency, CTLFLAG_RD, + &arm_pll_frequency, 0, "Zynq ARM PLL Frequency"); + +static int ddr_pll_frequency; +SYSCTL_INT(_hw_zynq, OID_AUTO, ddr_pll_frequency, CTLFLAG_RD, + &ddr_pll_frequency, 0, "Zynq DDR PLL Frequency"); + static void zy7_slcr_unlock(struct zy7_slcr_softc *sc) { @@ -189,6 +207,54 @@ ZSLCR_UNLOCK(sc); } +/* Override cgem_set_refclk() in gigabit ethernet driver + * (sys/dev/cadence/if_cgem.c). This function is called to + * request a change in the gem's reference clock speed. + */ +int +cgem_set_ref_clk(int unit, int frequency) +{ + struct zy7_slcr_softc *sc = zy7_slcr_softc_p; + int div0, div1; + + if (!sc) + return (-1); + + /* Find suitable divisor pairs. Round result to nearest khz + * to test for match. + */ + for (div1 = 1; div1 <= ZY7_SLCR_GEM_CLK_CTRL_DIVISOR1_MAX; div1++) { + div0 = (io_pll_frequency + div1 * frequency / 2) / + div1 / frequency; + if (div0 > 0 && div0 <= ZY7_SLCR_GEM_CLK_CTRL_DIVISOR_MAX && + ((io_pll_frequency / div0 / div1) + 500) / 1000 == + (frequency + 500) / 1000) + break; + } + + if (div1 > ZY7_SLCR_GEM_CLK_CTRL_DIVISOR1_MAX) + return (-1); + + ZSLCR_LOCK(sc); + + /* Unlock SLCR registers. */ + zy7_slcr_unlock(sc); + + /* Modify GEM reference clock. */ + WR4(sc, unit ? ZY7_SLCR_GEM1_CLK_CTRL : ZY7_SLCR_GEM0_CLK_CTRL, + (div1 << ZY7_SLCR_GEM_CLK_CTRL_DIVISOR1_SHIFT) | + (div0 << ZY7_SLCR_GEM_CLK_CTRL_DIVISOR_SHIFT) | + ZY7_SLCR_GEM_CLK_CTRL_SRCSEL_IO_PLL | + ZY7_SLCR_GEM_CLK_CTRL_CLKACT); + + /* Lock SLCR registers. */ + zy7_slcr_lock(sc); + + ZSLCR_UNLOCK(sc); + + return (0); +} + static int zy7_slcr_probe(device_t dev) { @@ -208,8 +274,13 @@ { struct zy7_slcr_softc *sc = device_get_softc(dev); int rid; + phandle_t node; + pcell_t cell; uint32_t bootmode; uint32_t pss_idcode; + uint32_t arm_pll_ctrl; + uint32_t ddr_pll_ctrl; + uint32_t io_pll_ctrl; static char *bootdev_names[] = { "JTAG", "Quad-SPI", "NOR", "(3?)", "NAND", "SD Card", "(6?)", "(7?)" @@ -260,6 +331,53 @@ zynq_reboot_status = RD4(sc, ZY7_SLCR_REBOOT_STAT); + /* Derive PLL frequencies from PS_CLK. */ + node = ofw_bus_get_node(dev); + if (OF_getprop(node, "clock-frequency", &cell, sizeof(cell)) > 0) + ps_clk_frequency = fdt32_to_cpu(cell); + else + ps_clk_frequency = ZYNQ_DEFAULT_PS_CLK_FREQUENCY; + + arm_pll_ctrl = RD4(sc, ZY7_SLCR_ARM_PLL_CTRL); + ddr_pll_ctrl = RD4(sc, ZY7_SLCR_DDR_PLL_CTRL); + io_pll_ctrl = RD4(sc, ZY7_SLCR_IO_PLL_CTRL); + + /* Determine ARM PLL frequency. */ + if (((arm_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) == 0 && + (arm_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_FORCE) != 0) || + ((arm_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) != 0 && + (bootmode & ZY7_SLCR_BOOT_MODE_PLL_BYPASS) != 0)) + /* PLL is bypassed. */ + arm_pll_frequency = ps_clk_frequency; + else + arm_pll_frequency = ps_clk_frequency * + ((arm_pll_ctrl & ZY7_SLCR_PLL_CTRL_FDIV_MASK) >> + ZY7_SLCR_PLL_CTRL_FDIV_SHIFT); + + /* Determine DDR PLL frequency. */ + if (((ddr_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) == 0 && + (ddr_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_FORCE) != 0) || + ((ddr_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) != 0 && + (bootmode & ZY7_SLCR_BOOT_MODE_PLL_BYPASS) != 0)) + /* PLL is bypassed. */ + ddr_pll_frequency = ps_clk_frequency; + else + ddr_pll_frequency = ps_clk_frequency * + ((ddr_pll_ctrl & ZY7_SLCR_PLL_CTRL_FDIV_MASK) >> + ZY7_SLCR_PLL_CTRL_FDIV_SHIFT); + + /* Determine IO PLL frequency. */ + if (((io_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) == 0 && + (io_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_FORCE) != 0) || + ((io_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) != 0 && + (bootmode & ZY7_SLCR_BOOT_MODE_PLL_BYPASS) != 0)) + /* PLL is bypassed. */ + io_pll_frequency = ps_clk_frequency; + else + io_pll_frequency = ps_clk_frequency * + ((io_pll_ctrl & ZY7_SLCR_PLL_CTRL_FDIV_MASK) >> + ZY7_SLCR_PLL_CTRL_FDIV_SHIFT); + /* Lock SLCR registers. */ zy7_slcr_lock(sc); Index: sys/arm/xilinx/zy7_slcr.h =================================================================== --- sys/arm/xilinx/zy7_slcr.h (revision 267546) +++ sys/arm/xilinx/zy7_slcr.h (working copy) @@ -126,6 +126,18 @@ #define ZY7_SLCR_GEM1_RCLK_CTRL 0x013c #define ZY7_SLCR_GEM0_CLK_CTRL 0x0140 #define ZY7_SLCR_GEM1_CLK_CTRL 0x0144 +#define ZY7_SLCR_GEM_CLK_CTRL_DIVISOR1_MASK (0x3f<<20) +#define ZY7_SLCR_GEM_CLK_CTRL_DIVISOR1_SHIFT 20 +#define ZY7_SLCR_GEM_CLK_CTRL_DIVISOR1_MAX 0x3f +#define ZY7_SLCR_GEM_CLK_CTRL_DIVISOR_MASK (0x3f<<8) +#define ZY7_SLCR_GEM_CLK_CTRL_DIVISOR_SHIFT 8 +#define ZY7_SLCR_GEM_CLK_CTRL_DIVISOR_MAX 0x3f +#define ZY7_SLCR_GEM_CLK_CTRL_SRCSEL_MASK (7<<4) +#define ZY7_SLCR_GEM_CLK_CTRL_SRCSEL_IO_PLL (0<<4) +#define ZY7_SLCR_GEM_CLK_CTRL_SRCSEL_ARM_PLL (2<<4) +#define ZY7_SLCR_GEM_CLK_CTRL_SRCSEL_DDR_PLL (3<<4) +#define ZY7_SLCR_GEM_CLK_CTRL_SRCSEL_EMIO_CLK (4<<4) +#define ZY7_SLCR_GEM_CLK_CTRL_CLKACT 1 #define ZY7_SLCR_SMC_CLK_CTRL 0x0148 #define ZY7_SLCR_LQSPI_CLK_CTRL 0x014c #define ZY7_SLCR_SDIO_CLK_CTRL 0x0150 @@ -274,6 +286,7 @@ #ifdef _KERNEL extern void zy7_slcr_preload_pl(void); -extern void zy7_slcr_postload_pl(int); +extern void zy7_slcr_postload_pl(int en_level_shifters); +extern int cgem_set_ref_clk(int unit, int frequency); #endif #endif /* _ZY7_SLCR_H_ */ Index: sys/boot/fdt/dts/arm/zedboard.dts =================================================================== --- sys/boot/fdt/dts/arm/zedboard.dts (revision 267806) +++ sys/boot/fdt/dts/arm/zedboard.dts (working copy) @@ -63,6 +63,7 @@ slcr: slcr@7000 { compatible = "xlnx,zy7_slcr"; reg = <0x0 0x1000>; + clock-frequency = <33333333>; // 33Mhz PS_CLK }; // Interrupt controller @@ -175,6 +176,7 @@ reg = <0xb000 0x1000>; interrupts = <54 55>; interrupt-parent = <&GIC>; + ref-clock-num = <0>; }; // SDIO Index: sys/dev/cadence/if_cgem.c =================================================================== --- sys/dev/cadence/if_cgem.c (revision 267546) +++ sys/dev/cadence/if_cgem.c (working copy) @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2012-2013 Thomas Skibo + * Copyright (c) 2012-2014 Thomas Skibo * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -108,6 +108,7 @@ void *intrhand; struct callout tick_ch; uint32_t net_ctl_shadow; + int ref_clk_num; u_char eaddr[6]; bus_dma_tag_t desc_dma_tag; @@ -149,6 +150,9 @@ #define CGEM_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_mtx) #define CGEM_ASSERT_LOCKED(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) +/* Allow platforms to optionally provide a way to set the reference clock. */ +int cgem_set_ref_clk(int unit, int frequency); + static devclass_t cgem_devclass; static int cgem_probe(device_t dev); @@ -707,47 +719,18 @@ CGEM_UNLOCK(sc); } -/* Respond to changes in media. */ static void -cgem_media_update(struct cgem_softc *sc, int active) -{ - uint32_t net_cfg; - - CGEM_ASSERT_LOCKED(sc); - - /* Update hardware to reflect phy status. */ - net_cfg = RD4(sc, CGEM_NET_CFG); - net_cfg &= ~(CGEM_NET_CFG_SPEED100 | CGEM_NET_CFG_GIGE_EN | - CGEM_NET_CFG_FULL_DUPLEX); - - if (IFM_SUBTYPE(active) == IFM_1000_T) - net_cfg |= (CGEM_NET_CFG_SPEED100 | CGEM_NET_CFG_GIGE_EN); - else if (IFM_SUBTYPE(active) == IFM_100_TX) - net_cfg |= CGEM_NET_CFG_SPEED100; - - if ((active & IFM_FDX) != 0) - net_cfg |= CGEM_NET_CFG_FULL_DUPLEX; - WR4(sc, CGEM_NET_CFG, net_cfg); -} - -static void cgem_tick(void *arg) { struct cgem_softc *sc = (struct cgem_softc *)arg; struct mii_data *mii; - int active; CGEM_ASSERT_LOCKED(sc); /* Poll the phy. */ if (sc->miibus != NULL) { mii = device_get_softc(sc->miibus); - active = mii->mii_media_active; mii_tick(mii); - if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == - (IFM_ACTIVE | IFM_AVALID) && - active != mii->mii_media_active) - cgem_media_update(sc, mii->mii_media_active); } /* Next callout in one second. */ @@ -894,7 +884,6 @@ mii = device_get_softc(sc->miibus); mii_pollstat(mii); - cgem_media_update(sc, mii->mii_media_active); cgem_start_locked(sc->ifp); callout_reset(&sc->tick_ch, hz, cgem_tick, sc); @@ -1073,12 +1066,13 @@ { struct cgem_softc *sc = (struct cgem_softc *) ifp->if_softc; struct mii_data *mii; + int error; mii = device_get_softc(sc->miibus); CGEM_LOCK(sc); - mii_mediachg(mii); + error = mii_mediachg(mii); CGEM_UNLOCK(sc); - return (0); + return (error); } static void @@ -1148,7 +1142,61 @@ return (0); } +/* + * Overridable weak symbol cgem_set_ref_clk(). This allows platforms to + * provide a function to set the cgem's reference clock. + */ +static int __used +cgem_default_set_ref_clk(int unit, int frequency) +{ + return 0; +} +__weak_reference(cgem_default_set_ref_clk, cgem_set_ref_clk); + +static void +cgem_miibus_statchg(device_t dev) +{ + struct cgem_softc *sc; + struct mii_data *mii; + uint32_t net_cfg; + int ref_clk_freq; + + sc = device_get_softc(dev); + + mii = device_get_softc(sc->miibus); + + if ((mii->mii_media_status & IFM_AVALID) != 0) { + /* Update hardware to reflect phy status. */ + net_cfg = RD4(sc, CGEM_NET_CFG); + net_cfg &= ~(CGEM_NET_CFG_SPEED100 | CGEM_NET_CFG_GIGE_EN | + CGEM_NET_CFG_FULL_DUPLEX); + + switch (IFM_SUBTYPE(mii->mii_media_active)) { + case IFM_1000_T: + net_cfg |= (CGEM_NET_CFG_SPEED100 | + CGEM_NET_CFG_GIGE_EN); + ref_clk_freq = 125000000; + break; + case IFM_100_TX: + net_cfg |= CGEM_NET_CFG_SPEED100; + ref_clk_freq = 25000000; + break; + default: + ref_clk_freq = 2500000; + } + + if ((mii->mii_media_active & IFM_FDX) != 0) + net_cfg |= CGEM_NET_CFG_FULL_DUPLEX; + WR4(sc, CGEM_NET_CFG, net_cfg); + + /* Set the reference clock if necessary. */ + if (cgem_set_ref_clk(sc->ref_clk_num, ref_clk_freq)) + device_printf(dev, "could not set ref clk%d to %d.\n", + sc->ref_clk_num, ref_clk_freq); + } +} + static int cgem_probe(device_t dev) { @@ -1165,12 +1213,20 @@ { struct cgem_softc *sc = device_get_softc(dev); struct ifnet *ifp = NULL; + phandle_t node; + pcell_t cell; int rid, err; u_char eaddr[ETHER_ADDR_LEN]; sc->dev = dev; CGEM_LOCK_INIT(sc); + /* Get reference clock number and base divider from fdt. */ + node = ofw_bus_get_node(dev); + sc->ref_clk_num = 0; + if (OF_getprop(node, "ref-clock-num", &cell, sizeof(cell)) > 0) + sc->ref_clk_num = fdt32_to_cpu(cell); + /* Get memory resource. */ rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, @@ -1364,6 +1414,7 @@ /* MII interface */ DEVMETHOD(miibus_readreg, cgem_miibus_readreg), DEVMETHOD(miibus_writereg, cgem_miibus_writereg), + DEVMETHOD(miibus_statchg, cgem_miibus_statchg), DEVMETHOD_END }; --------------030800060005090008020207--