1249997Swkoszek/*- 2250015Swkoszek * Copyright (c) 2013 Thomas Skibo 3249997Swkoszek * All rights reserved. 4250015Swkoszek * 5249997Swkoszek * Redistribution and use in source and binary forms, with or without 6250015Swkoszek * modification, are permitted provided that the following conditions 7250015Swkoszek * are met: 8250015Swkoszek * 1. Redistributions of source code must retain the above copyright 9250015Swkoszek * notice, this list of conditions and the following disclaimer. 10250015Swkoszek * 2. Redistributions in binary form must reproduce the above copyright 11250015Swkoszek * notice, this list of conditions and the following disclaimer in the 12250015Swkoszek * documentation and/or other materials provided with the distribution. 13250015Swkoszek * 14250015Swkoszek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15250015Swkoszek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16249997Swkoszek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17250015Swkoszek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18250015Swkoszek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19250015Swkoszek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20250015Swkoszek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21250015Swkoszek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22249997Swkoszek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23250015Swkoszek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24250015Swkoszek * SUCH DAMAGE. 25249997Swkoszek * 26250015Swkoszek * $FreeBSD$ 27249997Swkoszek */ 28249997Swkoszek 29250015Swkoszek/* 30250015Swkoszek * Zynq-700 SLCR driver. Provides hooks for cpu_reset and PL control stuff. 31249997Swkoszek * In the future, maybe MIO control, clock control, etc. could go here. 32249997Swkoszek * 33249997Swkoszek * Reference: Zynq-7000 All Programmable SoC Technical Reference Manual. 34249997Swkoszek * (v1.4) November 16, 2012. Xilinx doc UG585. 35249997Swkoszek */ 36249997Swkoszek 37249997Swkoszek#include <sys/cdefs.h> 38249997Swkoszek__FBSDID("$FreeBSD$"); 39249997Swkoszek 40249997Swkoszek#include <sys/param.h> 41249997Swkoszek#include <sys/systm.h> 42249997Swkoszek#include <sys/conf.h> 43249997Swkoszek#include <sys/kernel.h> 44249997Swkoszek#include <sys/module.h> 45249997Swkoszek#include <sys/lock.h> 46249997Swkoszek#include <sys/mutex.h> 47249997Swkoszek#include <sys/resource.h> 48249997Swkoszek#include <sys/sysctl.h> 49249997Swkoszek#include <sys/rman.h> 50249997Swkoszek 51249997Swkoszek#include <machine/bus.h> 52249997Swkoszek#include <machine/resource.h> 53249997Swkoszek#include <machine/stdarg.h> 54249997Swkoszek 55249997Swkoszek#include <dev/fdt/fdt_common.h> 56249997Swkoszek#include <dev/ofw/ofw_bus.h> 57249997Swkoszek#include <dev/ofw/ofw_bus_subr.h> 58249997Swkoszek 59249997Swkoszek#include <arm/xilinx/zy7_slcr.h> 60249997Swkoszek 61249997Swkoszekstruct zy7_slcr_softc { 62249997Swkoszek device_t dev; 63249997Swkoszek struct mtx sc_mtx; 64249997Swkoszek struct resource *mem_res; 65249997Swkoszek}; 66249997Swkoszek 67249997Swkoszekstatic struct zy7_slcr_softc *zy7_slcr_softc_p; 68249997Swkoszekextern void (*zynq7_cpu_reset); 69249997Swkoszek 70249997Swkoszek#define ZSLCR_LOCK(sc) mtx_lock(&(sc)->sc_mtx) 71249997Swkoszek#define ZSLCR_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) 72249997Swkoszek#define ZSLCR_LOCK_INIT(sc) \ 73249997Swkoszek mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), \ 74273645Sian "zy7_slcr", MTX_DEF) 75249997Swkoszek#define ZSLCR_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); 76249997Swkoszek 77249997Swkoszek#define RD4(sc, off) (bus_read_4((sc)->mem_res, (off))) 78249997Swkoszek#define WR4(sc, off, val) (bus_write_4((sc)->mem_res, (off), (val))) 79249997Swkoszek 80273645Sian#define ZYNQ_DEFAULT_PS_CLK_FREQUENCY 33333333 /* 33.3 Mhz */ 81249997Swkoszek 82273645Sian 83249997SwkoszekSYSCTL_NODE(_hw, OID_AUTO, zynq, CTLFLAG_RD, 0, "Xilinx Zynq-7000"); 84249997Swkoszek 85249997Swkoszekstatic char zynq_bootmode[64]; 86249997SwkoszekSYSCTL_STRING(_hw_zynq, OID_AUTO, bootmode, CTLFLAG_RD, zynq_bootmode, 0, 87249997Swkoszek "Zynq boot mode"); 88249997Swkoszek 89273645Sianstatic char zynq_pssid[100]; 90249997SwkoszekSYSCTL_STRING(_hw_zynq, OID_AUTO, pssid, CTLFLAG_RD, zynq_pssid, 0, 91249997Swkoszek "Zynq PSS IDCODE"); 92249997Swkoszek 93249997Swkoszekstatic uint32_t zynq_reboot_status; 94249997SwkoszekSYSCTL_INT(_hw_zynq, OID_AUTO, reboot_status, CTLFLAG_RD, &zynq_reboot_status, 95249997Swkoszek 0, "Zynq REBOOT_STATUS register"); 96249997Swkoszek 97273645Sianstatic int ps_clk_frequency; 98273645SianSYSCTL_INT(_hw_zynq, OID_AUTO, ps_clk_frequency, CTLFLAG_RD, &ps_clk_frequency, 99273645Sian 0, "Zynq PS_CLK Frequency"); 100273645Sian 101273645Sianstatic int io_pll_frequency; 102273645SianSYSCTL_INT(_hw_zynq, OID_AUTO, io_pll_frequency, CTLFLAG_RD, &io_pll_frequency, 103273645Sian 0, "Zynq IO PLL Frequency"); 104273645Sian 105273645Sianstatic int arm_pll_frequency; 106273645SianSYSCTL_INT(_hw_zynq, OID_AUTO, arm_pll_frequency, CTLFLAG_RD, 107273645Sian &arm_pll_frequency, 0, "Zynq ARM PLL Frequency"); 108273645Sian 109273645Sianstatic int ddr_pll_frequency; 110273645SianSYSCTL_INT(_hw_zynq, OID_AUTO, ddr_pll_frequency, CTLFLAG_RD, 111273645Sian &ddr_pll_frequency, 0, "Zynq DDR PLL Frequency"); 112273645Sian 113249997Swkoszekstatic void 114249997Swkoszekzy7_slcr_unlock(struct zy7_slcr_softc *sc) 115249997Swkoszek{ 116249997Swkoszek 117249997Swkoszek /* Unlock SLCR with magic number. */ 118249997Swkoszek WR4(sc, ZY7_SLCR_UNLOCK, ZY7_SLCR_UNLOCK_MAGIC); 119249997Swkoszek} 120249997Swkoszek 121249997Swkoszekstatic void 122249997Swkoszekzy7_slcr_lock(struct zy7_slcr_softc *sc) 123249997Swkoszek{ 124249997Swkoszek 125249997Swkoszek /* Lock SLCR with magic number. */ 126249997Swkoszek WR4(sc, ZY7_SLCR_LOCK, ZY7_SLCR_LOCK_MAGIC); 127249997Swkoszek} 128249997Swkoszek 129249997Swkoszek 130249997Swkoszekstatic void 131249997Swkoszekzy7_slcr_cpu_reset(void) 132249997Swkoszek{ 133249997Swkoszek struct zy7_slcr_softc *sc = zy7_slcr_softc_p; 134249997Swkoszek 135249997Swkoszek /* Unlock SLCR registers. */ 136249997Swkoszek zy7_slcr_unlock(sc); 137249997Swkoszek 138249997Swkoszek /* This has something to do with a work-around so the fsbl will load 139249997Swkoszek * the bitstream after soft-reboot. It's very important. 140249997Swkoszek */ 141249997Swkoszek WR4(sc, ZY7_SLCR_REBOOT_STAT, 142249997Swkoszek RD4(sc, ZY7_SLCR_REBOOT_STAT) & 0xf0ffffff); 143249997Swkoszek 144249997Swkoszek /* Soft reset */ 145249997Swkoszek WR4(sc, ZY7_SLCR_PSS_RST_CTRL, ZY7_SLCR_PSS_RST_CTRL_SOFT_RESET); 146249997Swkoszek 147249997Swkoszek for (;;) 148249997Swkoszek ; 149249997Swkoszek} 150249997Swkoszek 151249997Swkoszek/* Assert PL resets and disable level shifters in preparation of programming 152249997Swkoszek * the PL (FPGA) section. Called from zy7_devcfg.c. 153249997Swkoszek */ 154249997Swkoszekvoid 155249997Swkoszekzy7_slcr_preload_pl(void) 156249997Swkoszek{ 157249997Swkoszek struct zy7_slcr_softc *sc = zy7_slcr_softc_p; 158249997Swkoszek 159249997Swkoszek if (!sc) 160249997Swkoszek return; 161249997Swkoszek 162249997Swkoszek ZSLCR_LOCK(sc); 163249997Swkoszek 164249997Swkoszek /* Unlock SLCR registers. */ 165249997Swkoszek zy7_slcr_unlock(sc); 166249997Swkoszek 167249997Swkoszek /* Assert top level output resets. */ 168249997Swkoszek WR4(sc, ZY7_SLCR_FPGA_RST_CTRL, ZY7_SLCR_FPGA_RST_CTRL_RST_ALL); 169249997Swkoszek 170249997Swkoszek /* Disable all level shifters. */ 171249997Swkoszek WR4(sc, ZY7_SLCR_LVL_SHFTR_EN, 0); 172249997Swkoszek 173249997Swkoszek /* Lock SLCR registers. */ 174249997Swkoszek zy7_slcr_lock(sc); 175249997Swkoszek 176249997Swkoszek ZSLCR_UNLOCK(sc); 177249997Swkoszek} 178249997Swkoszek 179249997Swkoszek/* After PL configuration, enable level shifters and deassert top-level 180249997Swkoszek * PL resets. Called from zy7_devcfg.c. Optionally, the level shifters 181249997Swkoszek * can be left disabled but that's rare of an FPGA application. That option 182249997Swkoszek * is controled by a sysctl in the devcfg driver. 183249997Swkoszek */ 184249997Swkoszekvoid 185249997Swkoszekzy7_slcr_postload_pl(int en_level_shifters) 186249997Swkoszek{ 187249997Swkoszek struct zy7_slcr_softc *sc = zy7_slcr_softc_p; 188249997Swkoszek 189249997Swkoszek if (!sc) 190249997Swkoszek return; 191249997Swkoszek 192249997Swkoszek ZSLCR_LOCK(sc); 193249997Swkoszek 194249997Swkoszek /* Unlock SLCR registers. */ 195249997Swkoszek zy7_slcr_unlock(sc); 196249997Swkoszek 197249997Swkoszek if (en_level_shifters) 198249997Swkoszek /* Enable level shifters. */ 199249997Swkoszek WR4(sc, ZY7_SLCR_LVL_SHFTR_EN, ZY7_SLCR_LVL_SHFTR_EN_ALL); 200249997Swkoszek 201249997Swkoszek /* Deassert top level output resets. */ 202249997Swkoszek WR4(sc, ZY7_SLCR_FPGA_RST_CTRL, 0); 203249997Swkoszek 204249997Swkoszek /* Lock SLCR registers. */ 205249997Swkoszek zy7_slcr_lock(sc); 206249997Swkoszek 207249997Swkoszek ZSLCR_UNLOCK(sc); 208249997Swkoszek} 209249997Swkoszek 210273645Sian/* Override cgem_set_refclk() in gigabit ethernet driver 211273645Sian * (sys/dev/cadence/if_cgem.c). This function is called to 212273645Sian * request a change in the gem's reference clock speed. 213273645Sian */ 214273645Sianint 215273645Siancgem_set_ref_clk(int unit, int frequency) 216273645Sian{ 217273645Sian struct zy7_slcr_softc *sc = zy7_slcr_softc_p; 218273645Sian int div0, div1; 219273645Sian 220273645Sian if (!sc) 221273645Sian return (-1); 222273645Sian 223273645Sian /* Find suitable divisor pairs. Round result to nearest khz 224273645Sian * to test for match. 225273645Sian */ 226273645Sian for (div1 = 1; div1 <= ZY7_SLCR_GEM_CLK_CTRL_DIVISOR1_MAX; div1++) { 227273645Sian div0 = (io_pll_frequency + div1 * frequency / 2) / 228273645Sian div1 / frequency; 229273645Sian if (div0 > 0 && div0 <= ZY7_SLCR_GEM_CLK_CTRL_DIVISOR_MAX && 230273645Sian ((io_pll_frequency / div0 / div1) + 500) / 1000 == 231273645Sian (frequency + 500) / 1000) 232273645Sian break; 233273645Sian } 234273645Sian 235273645Sian if (div1 > ZY7_SLCR_GEM_CLK_CTRL_DIVISOR1_MAX) 236273645Sian return (-1); 237273645Sian 238273645Sian ZSLCR_LOCK(sc); 239273645Sian 240273645Sian /* Unlock SLCR registers. */ 241273645Sian zy7_slcr_unlock(sc); 242273645Sian 243273645Sian /* Modify GEM reference clock. */ 244273645Sian WR4(sc, unit ? ZY7_SLCR_GEM1_CLK_CTRL : ZY7_SLCR_GEM0_CLK_CTRL, 245273645Sian (div1 << ZY7_SLCR_GEM_CLK_CTRL_DIVISOR1_SHIFT) | 246273645Sian (div0 << ZY7_SLCR_GEM_CLK_CTRL_DIVISOR_SHIFT) | 247273645Sian ZY7_SLCR_GEM_CLK_CTRL_SRCSEL_IO_PLL | 248273645Sian ZY7_SLCR_GEM_CLK_CTRL_CLKACT); 249273645Sian 250273645Sian /* Lock SLCR registers. */ 251273645Sian zy7_slcr_lock(sc); 252273645Sian 253273645Sian ZSLCR_UNLOCK(sc); 254273645Sian 255273645Sian return (0); 256273645Sian} 257273645Sian 258249997Swkoszekstatic int 259249997Swkoszekzy7_slcr_probe(device_t dev) 260249997Swkoszek{ 261266152Sian 262266152Sian if (!ofw_bus_status_okay(dev)) 263266152Sian return (ENXIO); 264266152Sian 265249997Swkoszek if (!ofw_bus_is_compatible(dev, "xlnx,zy7_slcr")) 266249997Swkoszek return (ENXIO); 267249997Swkoszek 268249997Swkoszek device_set_desc(dev, "Zynq-7000 slcr block"); 269249997Swkoszek return (0); 270249997Swkoszek} 271249997Swkoszek 272249997Swkoszekstatic int 273249997Swkoszekzy7_slcr_attach(device_t dev) 274249997Swkoszek{ 275249997Swkoszek struct zy7_slcr_softc *sc = device_get_softc(dev); 276249997Swkoszek int rid; 277273645Sian phandle_t node; 278273645Sian pcell_t cell; 279249997Swkoszek uint32_t bootmode; 280249997Swkoszek uint32_t pss_idcode; 281273645Sian uint32_t arm_pll_ctrl; 282273645Sian uint32_t ddr_pll_ctrl; 283273645Sian uint32_t io_pll_ctrl; 284249997Swkoszek static char *bootdev_names[] = { 285249997Swkoszek "JTAG", "Quad-SPI", "NOR", "(3?)", 286249997Swkoszek "NAND", "SD Card", "(6?)", "(7?)" 287249997Swkoszek }; 288249997Swkoszek 289249997Swkoszek /* Allow only one attach. */ 290249997Swkoszek if (zy7_slcr_softc_p != NULL) 291249997Swkoszek return (ENXIO); 292249997Swkoszek 293249997Swkoszek sc->dev = dev; 294249997Swkoszek 295249997Swkoszek ZSLCR_LOCK_INIT(sc); 296249997Swkoszek 297249997Swkoszek /* Get memory resource. */ 298249997Swkoszek rid = 0; 299249997Swkoszek sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 300249997Swkoszek RF_ACTIVE); 301249997Swkoszek if (sc->mem_res == NULL) { 302249997Swkoszek device_printf(dev, "could not allocate memory resources.\n"); 303249997Swkoszek return (ENOMEM); 304249997Swkoszek } 305249997Swkoszek 306249997Swkoszek /* Hook up cpu_reset. */ 307249997Swkoszek zy7_slcr_softc_p = sc; 308249997Swkoszek zynq7_cpu_reset = zy7_slcr_cpu_reset; 309249997Swkoszek 310249997Swkoszek /* Read info and set sysctls. */ 311249997Swkoszek bootmode = RD4(sc, ZY7_SLCR_BOOT_MODE); 312249997Swkoszek snprintf(zynq_bootmode, sizeof(zynq_bootmode), 313249997Swkoszek "0x%x: boot device: %s", bootmode, 314249997Swkoszek bootdev_names[bootmode & ZY7_SLCR_BOOT_MODE_BOOTDEV_MASK]); 315249997Swkoszek 316249997Swkoszek pss_idcode = RD4(sc, ZY7_SLCR_PSS_IDCODE); 317249997Swkoszek snprintf(zynq_pssid, sizeof(zynq_pssid), 318249997Swkoszek "0x%x: manufacturer: 0x%x device: 0x%x " 319249997Swkoszek "family: 0x%x sub-family: 0x%x rev: 0x%x", 320249997Swkoszek pss_idcode, 321249997Swkoszek (pss_idcode & ZY7_SLCR_PSS_IDCODE_MNFR_ID_MASK) >> 322249997Swkoszek ZY7_SLCR_PSS_IDCODE_MNFR_ID_SHIFT, 323249997Swkoszek (pss_idcode & ZY7_SLCR_PSS_IDCODE_DEVICE_MASK) >> 324249997Swkoszek ZY7_SLCR_PSS_IDCODE_DEVICE_SHIFT, 325249997Swkoszek (pss_idcode & ZY7_SLCR_PSS_IDCODE_FAMILY_MASK) >> 326249997Swkoszek ZY7_SLCR_PSS_IDCODE_FAMILY_SHIFT, 327249997Swkoszek (pss_idcode & ZY7_SLCR_PSS_IDCODE_SUB_FAMILY_MASK) >> 328249997Swkoszek ZY7_SLCR_PSS_IDCODE_SUB_FAMILY_SHIFT, 329249997Swkoszek (pss_idcode & ZY7_SLCR_PSS_IDCODE_REVISION_MASK) >> 330249997Swkoszek ZY7_SLCR_PSS_IDCODE_REVISION_SHIFT); 331249997Swkoszek 332249997Swkoszek zynq_reboot_status = RD4(sc, ZY7_SLCR_REBOOT_STAT); 333249997Swkoszek 334273645Sian /* Derive PLL frequencies from PS_CLK. */ 335273645Sian node = ofw_bus_get_node(dev); 336273645Sian if (OF_getprop(node, "clock-frequency", &cell, sizeof(cell)) > 0) 337273645Sian ps_clk_frequency = fdt32_to_cpu(cell); 338273645Sian else 339273645Sian ps_clk_frequency = ZYNQ_DEFAULT_PS_CLK_FREQUENCY; 340273645Sian 341273645Sian arm_pll_ctrl = RD4(sc, ZY7_SLCR_ARM_PLL_CTRL); 342273645Sian ddr_pll_ctrl = RD4(sc, ZY7_SLCR_DDR_PLL_CTRL); 343273645Sian io_pll_ctrl = RD4(sc, ZY7_SLCR_IO_PLL_CTRL); 344273645Sian 345273645Sian /* Determine ARM PLL frequency. */ 346273645Sian if (((arm_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) == 0 && 347273645Sian (arm_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_FORCE) != 0) || 348273645Sian ((arm_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) != 0 && 349273645Sian (bootmode & ZY7_SLCR_BOOT_MODE_PLL_BYPASS) != 0)) 350273645Sian /* PLL is bypassed. */ 351273645Sian arm_pll_frequency = ps_clk_frequency; 352273645Sian else 353273645Sian arm_pll_frequency = ps_clk_frequency * 354273645Sian ((arm_pll_ctrl & ZY7_SLCR_PLL_CTRL_FDIV_MASK) >> 355273645Sian ZY7_SLCR_PLL_CTRL_FDIV_SHIFT); 356273645Sian 357273645Sian /* Determine DDR PLL frequency. */ 358273645Sian if (((ddr_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) == 0 && 359273645Sian (ddr_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_FORCE) != 0) || 360273645Sian ((ddr_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) != 0 && 361273645Sian (bootmode & ZY7_SLCR_BOOT_MODE_PLL_BYPASS) != 0)) 362273645Sian /* PLL is bypassed. */ 363273645Sian ddr_pll_frequency = ps_clk_frequency; 364273645Sian else 365273645Sian ddr_pll_frequency = ps_clk_frequency * 366273645Sian ((ddr_pll_ctrl & ZY7_SLCR_PLL_CTRL_FDIV_MASK) >> 367273645Sian ZY7_SLCR_PLL_CTRL_FDIV_SHIFT); 368273645Sian 369273645Sian /* Determine IO PLL frequency. */ 370273645Sian if (((io_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) == 0 && 371273645Sian (io_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_FORCE) != 0) || 372273645Sian ((io_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) != 0 && 373273645Sian (bootmode & ZY7_SLCR_BOOT_MODE_PLL_BYPASS) != 0)) 374273645Sian /* PLL is bypassed. */ 375273645Sian io_pll_frequency = ps_clk_frequency; 376273645Sian else 377273645Sian io_pll_frequency = ps_clk_frequency * 378273645Sian ((io_pll_ctrl & ZY7_SLCR_PLL_CTRL_FDIV_MASK) >> 379273645Sian ZY7_SLCR_PLL_CTRL_FDIV_SHIFT); 380273645Sian 381249997Swkoszek /* Lock SLCR registers. */ 382249997Swkoszek zy7_slcr_lock(sc); 383249997Swkoszek 384249997Swkoszek return (0); 385249997Swkoszek} 386249997Swkoszek 387249997Swkoszekstatic int 388249997Swkoszekzy7_slcr_detach(device_t dev) 389249997Swkoszek{ 390249997Swkoszek struct zy7_slcr_softc *sc = device_get_softc(dev); 391249997Swkoszek 392249997Swkoszek bus_generic_detach(dev); 393249997Swkoszek 394249997Swkoszek /* Release memory resource. */ 395249997Swkoszek if (sc->mem_res != NULL) 396249997Swkoszek bus_release_resource(dev, SYS_RES_MEMORY, 397249997Swkoszek rman_get_rid(sc->mem_res), sc->mem_res); 398249997Swkoszek 399249997Swkoszek zy7_slcr_softc_p = NULL; 400249997Swkoszek zynq7_cpu_reset = NULL; 401249997Swkoszek 402249997Swkoszek ZSLCR_LOCK_DESTROY(sc); 403249997Swkoszek 404249997Swkoszek return (0); 405249997Swkoszek} 406249997Swkoszek 407249997Swkoszekstatic device_method_t zy7_slcr_methods[] = { 408249997Swkoszek /* device_if */ 409249997Swkoszek DEVMETHOD(device_probe, zy7_slcr_probe), 410249997Swkoszek DEVMETHOD(device_attach, zy7_slcr_attach), 411249997Swkoszek DEVMETHOD(device_detach, zy7_slcr_detach), 412249997Swkoszek 413249997Swkoszek DEVMETHOD_END 414249997Swkoszek}; 415249997Swkoszek 416249997Swkoszekstatic driver_t zy7_slcr_driver = { 417249997Swkoszek "zy7_slcr", 418249997Swkoszek zy7_slcr_methods, 419249997Swkoszek sizeof(struct zy7_slcr_softc), 420249997Swkoszek}; 421249997Swkoszekstatic devclass_t zy7_slcr_devclass; 422249997Swkoszek 423249997SwkoszekDRIVER_MODULE(zy7_slcr, simplebus, zy7_slcr_driver, zy7_slcr_devclass, 0, 0); 424249997SwkoszekMODULE_VERSION(zy7_slcr, 1); 425