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-7000 Devcfg driver. This allows programming the PL (FPGA) section 31249997Swkoszek * of Zynq. 32249997Swkoszek * 33249997Swkoszek * Reference: Zynq-7000 All Programmable SoC Technical Reference Manual. 34249997Swkoszek * (v1.4) November 16, 2012. Xilinx doc UG585. PL Configuration is 35249997Swkoszek * covered in section 6.4.5. 36249997Swkoszek */ 37249997Swkoszek 38249997Swkoszek#include <sys/cdefs.h> 39249997Swkoszek__FBSDID("$FreeBSD$"); 40249997Swkoszek 41249997Swkoszek#include <sys/param.h> 42249997Swkoszek#include <sys/systm.h> 43249997Swkoszek#include <sys/conf.h> 44249997Swkoszek#include <sys/kernel.h> 45249997Swkoszek#include <sys/module.h> 46249997Swkoszek#include <sys/sysctl.h> 47249997Swkoszek#include <sys/lock.h> 48249997Swkoszek#include <sys/mutex.h> 49249997Swkoszek#include <sys/resource.h> 50249997Swkoszek#include <sys/rman.h> 51249997Swkoszek#include <sys/uio.h> 52249997Swkoszek 53249997Swkoszek#include <machine/bus.h> 54249997Swkoszek#include <machine/resource.h> 55249997Swkoszek#include <machine/stdarg.h> 56249997Swkoszek 57249997Swkoszek#include <dev/fdt/fdt_common.h> 58249997Swkoszek#include <dev/ofw/ofw_bus.h> 59249997Swkoszek#include <dev/ofw/ofw_bus_subr.h> 60249997Swkoszek 61249997Swkoszek#include <arm/xilinx/zy7_slcr.h> 62249997Swkoszek 63249997Swkoszekstruct zy7_devcfg_softc { 64249997Swkoszek device_t dev; 65249997Swkoszek struct mtx sc_mtx; 66249997Swkoszek struct resource *mem_res; 67249997Swkoszek struct resource *irq_res; 68249997Swkoszek struct cdev *sc_ctl_dev; 69249997Swkoszek void *intrhandle; 70249997Swkoszek 71249997Swkoszek bus_dma_tag_t dma_tag; 72249997Swkoszek bus_dmamap_t dma_map; 73249997Swkoszek 74249997Swkoszek int is_open; 75279677Sgonzo 76279677Sgonzo struct sysctl_ctx_list sysctl_tree; 77279677Sgonzo struct sysctl_oid *sysctl_tree_top; 78249997Swkoszek}; 79249997Swkoszek 80249997Swkoszekstatic struct zy7_devcfg_softc *zy7_devcfg_softc_p; 81249997Swkoszek 82279677Sgonzo#define FCLK_NUM 4 83279677Sgonzo 84279677Sgonzostruct zy7_fclk_config { 85279677Sgonzo int source; 86279677Sgonzo int frequency; 87279677Sgonzo int actual_frequency; 88279677Sgonzo}; 89279677Sgonzo 90279677Sgonzostatic struct zy7_fclk_config fclk_configs[FCLK_NUM]; 91279677Sgonzo 92249997Swkoszek#define DEVCFG_SC_LOCK(sc) mtx_lock(&(sc)->sc_mtx) 93249997Swkoszek#define DEVCFG_SC_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) 94249997Swkoszek#define DEVCFG_SC_LOCK_INIT(sc) \ 95249997Swkoszek mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), \ 96249997Swkoszek "zy7_devcfg", MTX_DEF) 97249997Swkoszek#define DEVCFG_SC_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_mtx); 98249997Swkoszek#define DEVCFG_SC_ASSERT_LOCKED(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED); 99249997Swkoszek 100249997Swkoszek#define RD4(sc, off) (bus_read_4((sc)->mem_res, (off))) 101249997Swkoszek#define WR4(sc, off, val) (bus_write_4((sc)->mem_res, (off), (val))) 102249997Swkoszek 103249997SwkoszekSYSCTL_NODE(_hw, OID_AUTO, fpga, CTLFLAG_RD, 0, \ 104249997Swkoszek "Xilinx Zynq-7000 PL (FPGA) section"); 105249997Swkoszek 106249997Swkoszekstatic int zy7_devcfg_sysctl_pl_done(SYSCTL_HANDLER_ARGS); 107249997SwkoszekSYSCTL_PROC(_hw_fpga, OID_AUTO, pl_done, CTLTYPE_INT | CTLFLAG_RD, NULL, 0, 108249997Swkoszek zy7_devcfg_sysctl_pl_done, "I", "PL section config DONE signal"); 109249997Swkoszek 110249997Swkoszekstatic int zy7_en_level_shifters = 1; 111249997SwkoszekSYSCTL_INT(_hw_fpga, OID_AUTO, en_level_shifters, CTLFLAG_RW, 112249997Swkoszek &zy7_en_level_shifters, 0, 113249997Swkoszek "Enable PS-PL level shifters after device config"); 114249997Swkoszek 115249997Swkoszekstatic int zy7_ps_vers = 0; 116249997SwkoszekSYSCTL_INT(_hw, OID_AUTO, ps_vers, CTLFLAG_RD, &zy7_ps_vers, 0, 117249997Swkoszek "Zynq-7000 PS version"); 118249997Swkoszek 119279677Sgonzostatic int zy7_devcfg_fclk_sysctl_level_shifters(SYSCTL_HANDLER_ARGS); 120279677SgonzoSYSCTL_PROC(_hw_fpga, OID_AUTO, level_shifters, 121279677Sgonzo CTLFLAG_RW | CTLTYPE_INT, 122279677Sgonzo NULL, 0, zy7_devcfg_fclk_sysctl_level_shifters, 123279677Sgonzo "I", "Enable/disable level shifters"); 124249997Swkoszek 125249997Swkoszek/* cdev entry points. */ 126249997Swkoszekstatic int zy7_devcfg_open(struct cdev *, int, int, struct thread *); 127249997Swkoszekstatic int zy7_devcfg_write(struct cdev *, struct uio *, int); 128249997Swkoszekstatic int zy7_devcfg_close(struct cdev *, int, int, struct thread *); 129249997Swkoszek 130249997Swkoszekstruct cdevsw zy7_devcfg_cdevsw = { 131249997Swkoszek .d_version = D_VERSION, 132249997Swkoszek .d_open = zy7_devcfg_open, 133249997Swkoszek .d_write = zy7_devcfg_write, 134249997Swkoszek .d_close = zy7_devcfg_close, 135249997Swkoszek .d_name = "devcfg", 136249997Swkoszek}; 137249997Swkoszek 138249997Swkoszek/* Devcfg block registers. */ 139249997Swkoszek#define ZY7_DEVCFG_CTRL 0x0000 140249997Swkoszek#define ZY7_DEVCFG_CTRL_FORCE_RST (1<<31) 141249997Swkoszek#define ZY7_DEVCFG_CTRL_PCFG_PROG_B (1<<30) 142249997Swkoszek#define ZY7_DEVCFG_CTRL_PCFG_POR_CNT_4K (1<<29) 143249997Swkoszek#define ZY7_DEVCFG_CTRL_PCAP_PR (1<<27) 144249997Swkoszek#define ZY7_DEVCFG_CTRL_PCAP_MODE (1<<26) 145249997Swkoszek#define ZY7_DEVCFG_CTRL_QTR_PCAP_RATE_EN (1<<25) 146249997Swkoszek#define ZY7_DEVCFG_CTRL_MULTIBOOT_EN (1<<24) 147249997Swkoszek#define ZY7_DEVCFG_CTRL_JTAG_CHAIN_DIS (1<<23) 148249997Swkoszek#define ZY7_DEVCFG_CTRL_USER_MODE (1<<15) 149249997Swkoszek#define ZY7_DEVCFG_CTRL_RESVD_WR11 (3<<13) /* always write 11 */ 150249997Swkoszek#define ZY7_DEVCFG_CTRL_PCFG_AES_FUSE (1<<12) 151249997Swkoszek#define ZY7_DEVCFG_CTRL_PCFG_AES_EN_MASK (7<<9) /* all 1's or 0's */ 152249997Swkoszek#define ZY7_DEVCFG_CTRL_SEU_EN (1<<8) 153249997Swkoszek#define ZY7_DEVCFG_CTRL_SEC_EN (1<<7) 154249997Swkoszek#define ZY7_DEVCFG_CTRL_SPNIDEN (1<<6) 155249997Swkoszek#define ZY7_DEVCFG_CTRL_SPIDEN (1<<5) 156249997Swkoszek#define ZY7_DEVCFG_CTRL_NIDEN (1<<4) 157249997Swkoszek#define ZY7_DEVCFG_CTRL_DBGEN (1<<3) 158249997Swkoszek#define ZY7_DEVCFG_CTRL_DAP_EN_MASK (7<<0) /* all 1's to enable */ 159249997Swkoszek 160249997Swkoszek#define ZY7_DEVCFG_LOCK 0x004 161249997Swkoszek#define ZY7_DEVCFG_LOCK_AES_FUSE_LOCK (1<<4) 162249997Swkoszek#define ZY7_DEVCFG_LOCK_AES_EN (1<<3) 163249997Swkoszek#define ZY7_DEVCFG_LOCK_SEU_LOCK (1<<2) 164249997Swkoszek#define ZY7_DEVCFG_LOCK_SEC_LOCK (1<<1) 165249997Swkoszek#define ZY7_DEVCFG_LOCK_DBG_LOCK (1<<0) 166249997Swkoszek 167249997Swkoszek#define ZY7_DEVCFG_CFG 0x008 168249997Swkoszek#define ZY7_DEVCFG_CFG_RFIFO_TH_MASK (3<<10) 169249997Swkoszek#define ZY7_DEVCFG_CFG_WFIFO_TH_MASK (3<<8) 170249997Swkoszek#define ZY7_DEVCFG_CFG_RCLK_EDGE (1<<7) 171249997Swkoszek#define ZY7_DEVCFG_CFG_WCLK_EDGE (1<<6) 172249997Swkoszek#define ZY7_DEVCFG_CFG_DIS_SRC_INC (1<<5) 173249997Swkoszek#define ZY7_DEVCFG_CFG_DIS_DST_INC (1<<4) 174249997Swkoszek 175249997Swkoszek#define ZY7_DEVCFG_INT_STATUS 0x00C 176249997Swkoszek#define ZY7_DEVCFG_INT_MASK 0x010 177249997Swkoszek#define ZY7_DEVCFG_INT_PSS_GTS_USR_B (1<<31) 178249997Swkoszek#define ZY7_DEVCFG_INT_PSS_FST_CFG_B (1<<30) 179249997Swkoszek#define ZY7_DEVCFG_INT_PSS_GPWRDWN_B (1<<29) 180249997Swkoszek#define ZY7_DEVCFG_INT_PSS_GTS_CFG_B (1<<28) 181249997Swkoszek#define ZY7_DEVCFG_INT_CFG_RESET_B (1<<27) 182249997Swkoszek#define ZY7_DEVCFG_INT_AXI_WTO (1<<23) /* axi write timeout */ 183249997Swkoszek#define ZY7_DEVCFG_INT_AXI_WERR (1<<22) /* axi write err */ 184249997Swkoszek#define ZY7_DEVCFG_INT_AXI_RTO (1<<21) /* axi read timeout */ 185249997Swkoszek#define ZY7_DEVCFG_INT_AXI_RERR (1<<20) /* axi read err */ 186249997Swkoszek#define ZY7_DEVCFG_INT_RX_FIFO_OV (1<<18) /* rx fifo overflow */ 187249997Swkoszek#define ZY7_DEVCFG_INT_WR_FIFO_LVL (1<<17) /* wr fifo < level */ 188249997Swkoszek#define ZY7_DEVCFG_INT_RD_FIFO_LVL (1<<16) /* rd fifo >= level */ 189249997Swkoszek#define ZY7_DEVCFG_INT_DMA_CMD_ERR (1<<15) 190249997Swkoszek#define ZY7_DEVCFG_INT_DMA_Q_OV (1<<14) 191249997Swkoszek#define ZY7_DEVCFG_INT_DMA_DONE (1<<13) 192249997Swkoszek#define ZY7_DEVCFG_INT_DMA_PCAP_DONE (1<<12) 193249997Swkoszek#define ZY7_DEVCFG_INT_P2D_LEN_ERR (1<<11) 194249997Swkoszek#define ZY7_DEVCFG_INT_PCFG_HMAC_ERR (1<<6) 195249997Swkoszek#define ZY7_DEVCFG_INT_PCFG_SEU_ERR (1<<5) 196249997Swkoszek#define ZY7_DEVCFG_INT_PCFG_POR_B (1<<4) 197249997Swkoszek#define ZY7_DEVCFG_INT_PCFG_CFG_RST (1<<3) 198249997Swkoszek#define ZY7_DEVCFG_INT_PCFG_DONE (1<<2) 199249997Swkoszek#define ZY7_DEVCFG_INT_PCFG_INIT_PE (1<<1) 200249997Swkoszek#define ZY7_DEVCFG_INT_PCFG_INIT_NE (1<<0) 201249997Swkoszek#define ZY7_DEVCFG_INT_ERRORS 0x00f0f860 202249997Swkoszek#define ZY7_DEVCFG_INT_ALL 0xf8f7f87f 203249997Swkoszek 204249997Swkoszek#define ZY7_DEVCFG_STATUS 0x014 205249997Swkoszek#define ZY7_DEVCFG_STATUS_DMA_CMD_Q_F (1<<31) /* cmd queue full */ 206249997Swkoszek#define ZY7_DEVCFG_STATUS_DMA_CMD_Q_E (1<<30) /* cmd queue empty */ 207249997Swkoszek#define ZY7_DEVCFG_STATUS_DONE_COUNT_MASK (3<<28) 208249997Swkoszek#define ZY7_DEVCFG_STATUS_DONE_COUNT_SHIFT 28 209249997Swkoszek#define ZY7_DEVCFG_STATUS_RX_FIFO_LVL_MASK (0x1f<<20) 210249997Swkoszek#define ZY7_DEVCFG_STATUS_RX_FIFO_LVL_SHIFT 20 211249997Swkoszek#define ZY7_DEVCFG_STATUS_TX_FIFO_LVL_MASK (0x7f<<12) 212249997Swkoszek#define ZY7_DEVCFG_STATUS_TX_FIFO_LVL_SHIFT 12 213249997Swkoszek#define ZY7_DEVCFG_STATUS_PSS_GTS_USR_B (1<<11) 214249997Swkoszek#define ZY7_DEVCFG_STATUS_PSS_FST_CFG_B (1<<10) 215249997Swkoszek#define ZY7_DEVCFG_STATUS_PSS_GPWRDWN_B (1<<9) 216249997Swkoszek#define ZY7_DEVCFG_STATUS_PSS_GTS_CFG_B (1<<8) 217249997Swkoszek#define ZY7_DEVCFG_STATUS_ILL_APB_ACCE (1<<6) 218249997Swkoszek#define ZY7_DEVCFG_STATUS_PSS_CFG_RESET_B (1<<5) 219249997Swkoszek#define ZY7_DEVCFG_STATUS_PCFG_INIT (1<<4) 220249997Swkoszek#define ZY7_DEVCFG_STATUS_EFUSE_BBRAM_KEY_DIS (1<<3) 221249997Swkoszek#define ZY7_DEVCFG_STATUS_EFUSE_SEC_EN (1<<2) 222249997Swkoszek#define ZY7_DEVCFG_STATUS_EFUSE_JTAG_DIS (1<<1) 223249997Swkoszek 224249997Swkoszek#define ZY7_DEVCFG_DMA_SRC_ADDR 0x018 225249997Swkoszek#define ZY7_DEVCFG_DMA_DST_ADDR 0x01c 226249997Swkoszek#define ZY7_DEVCFG_DMA_ADDR_WAIT_PCAP 1 227249997Swkoszek#define ZY7_DEVCFG_DMA_ADDR_ILLEGAL 0xffffffff 228249997Swkoszek 229249997Swkoszek#define ZY7_DEVCFG_DMA_SRC_LEN 0x020 /* in 4-byte words. */ 230249997Swkoszek#define ZY7_DEVCFG_DMA_SRC_LEN_MAX 0x7ffffff 231249997Swkoszek#define ZY7_DEVCFG_DMA_DST_LEN 0x024 232249997Swkoszek#define ZY7_DEVCFG_ROM_SHADOW 0x028 233249997Swkoszek#define ZY7_DEVCFG_MULTIBOOT_ADDR 0x02c 234249997Swkoszek#define ZY7_DEVCFG_SW_ID 0x030 235249997Swkoszek#define ZY7_DEVCFG_UNLOCK 0x034 236249997Swkoszek#define ZY7_DEVCFG_UNLOCK_MAGIC 0x757bdf0d 237249997Swkoszek#define ZY7_DEVCFG_MCTRL 0x080 238249997Swkoszek#define ZY7_DEVCFG_MCTRL_PS_VERS_MASK (0xf<<28) 239249997Swkoszek#define ZY7_DEVCFG_MCTRL_PS_VERS_SHIFT 28 240249997Swkoszek#define ZY7_DEVCFG_MCTRL_PCFG_POR_B (1<<8) 241249997Swkoszek#define ZY7_DEVCFG_MCTRL_INT_PCAP_LPBK (1<<4) 242249997Swkoszek#define ZY7_DEVCFG_XADCIF_CFG 0x100 243249997Swkoszek#define ZY7_DEVCFG_XADCIF_INT_STAT 0x104 244249997Swkoszek#define ZY7_DEVCFG_XADCIF_INT_MASK 0x108 245249997Swkoszek#define ZY7_DEVCFG_XADCIF_MSTS 0x10c 246249997Swkoszek#define ZY7_DEVCFG_XADCIF_CMD_FIFO 0x110 247249997Swkoszek#define ZY7_DEVCFG_XADCIF_RD_FIFO 0x114 248249997Swkoszek#define ZY7_DEVCFG_XADCIF_MCTL 0x118 249249997Swkoszek 250279677Sgonzostatic int 251279677Sgonzozy7_devcfg_fclk_sysctl_source(SYSCTL_HANDLER_ARGS) 252279677Sgonzo{ 253279677Sgonzo char buf[4]; 254279677Sgonzo struct zy7_fclk_config *cfg; 255279677Sgonzo int unit; 256279677Sgonzo int error; 257249997Swkoszek 258279677Sgonzo cfg = arg1; 259279677Sgonzo unit = arg2; 260279677Sgonzo 261279677Sgonzo switch (cfg->source) { 262279677Sgonzo case ZY7_PL_FCLK_SRC_IO: 263279677Sgonzo case ZY7_PL_FCLK_SRC_IO_ALT: 264279677Sgonzo strncpy(buf, "IO", sizeof(buf)); 265279677Sgonzo break; 266279677Sgonzo case ZY7_PL_FCLK_SRC_DDR: 267279677Sgonzo strncpy(buf, "DDR", sizeof(buf)); 268279677Sgonzo break; 269279677Sgonzo case ZY7_PL_FCLK_SRC_ARM: 270279677Sgonzo strncpy(buf, "ARM", sizeof(buf)); 271279677Sgonzo break; 272279677Sgonzo default: 273279677Sgonzo strncpy(buf, "???", sizeof(buf)); 274279677Sgonzo break; 275279677Sgonzo } 276279677Sgonzo 277279677Sgonzo error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 278279677Sgonzo if (error != 0 || req->newptr == NULL) 279279677Sgonzo return (error); 280279677Sgonzo 281279677Sgonzo if (strcasecmp(buf, "io") == 0) 282279677Sgonzo cfg->source = ZY7_PL_FCLK_SRC_IO; 283279677Sgonzo else if (strcasecmp(buf, "ddr") == 0) 284279677Sgonzo cfg->source = ZY7_PL_FCLK_SRC_DDR; 285279677Sgonzo else if (strcasecmp(buf, "arm") == 0) 286279677Sgonzo cfg->source = ZY7_PL_FCLK_SRC_ARM; 287279677Sgonzo else 288279677Sgonzo return (EINVAL); 289279677Sgonzo 290279677Sgonzo zy7_pl_fclk_set_source(unit, cfg->source); 291279677Sgonzo if (cfg->frequency > 0) 292279677Sgonzo cfg->actual_frequency = zy7_pl_fclk_get_freq(unit); 293279677Sgonzo 294279677Sgonzo return (0); 295279677Sgonzo} 296279677Sgonzo 297279677Sgonzostatic int 298279677Sgonzozy7_devcfg_fclk_sysctl_freq(SYSCTL_HANDLER_ARGS) 299279677Sgonzo{ 300279677Sgonzo struct zy7_fclk_config *cfg; 301279677Sgonzo int unit; 302279677Sgonzo int error; 303279677Sgonzo int freq; 304279677Sgonzo int new_actual_freq; 305279677Sgonzo 306279677Sgonzo cfg = arg1; 307279677Sgonzo unit = arg2; 308279677Sgonzo 309279677Sgonzo freq = cfg->frequency; 310279677Sgonzo 311279677Sgonzo error = sysctl_handle_int(oidp, &freq, 0, req); 312279677Sgonzo if (error != 0 || req->newptr == NULL) 313279677Sgonzo return (error); 314279677Sgonzo 315279677Sgonzo if (freq > 0) { 316279677Sgonzo new_actual_freq = zy7_pl_fclk_set_freq(unit, freq); 317279677Sgonzo if (new_actual_freq < 0) 318279677Sgonzo return (EINVAL); 319279677Sgonzo if (!zy7_pl_fclk_enabled(unit)) 320279677Sgonzo zy7_pl_fclk_enable(unit); 321279677Sgonzo } 322279677Sgonzo else { 323279677Sgonzo zy7_pl_fclk_disable(unit); 324279677Sgonzo new_actual_freq = 0; 325279677Sgonzo } 326279677Sgonzo 327279677Sgonzo cfg->frequency = freq; 328279677Sgonzo cfg->actual_frequency = new_actual_freq; 329279677Sgonzo 330279677Sgonzo return (0); 331279677Sgonzo} 332279677Sgonzo 333279677Sgonzostatic int 334279677Sgonzozy7_devcfg_fclk_sysctl_level_shifters(SYSCTL_HANDLER_ARGS) 335279677Sgonzo{ 336279677Sgonzo int error, enabled; 337279677Sgonzo 338279677Sgonzo enabled = zy7_pl_level_shifters_enabled(); 339279677Sgonzo 340279677Sgonzo error = sysctl_handle_int(oidp, &enabled, 0, req); 341279677Sgonzo if (error != 0 || req->newptr == NULL) 342279677Sgonzo return (error); 343279677Sgonzo 344279677Sgonzo if (enabled) 345279677Sgonzo zy7_pl_level_shifters_enable(); 346279677Sgonzo else 347279677Sgonzo zy7_pl_level_shifters_disable(); 348279677Sgonzo 349279677Sgonzo return (0); 350279677Sgonzo} 351279677Sgonzo 352279677Sgonzostatic int 353279677Sgonzozy7_devcfg_init_fclk_sysctl(struct zy7_devcfg_softc *sc) 354279677Sgonzo{ 355279677Sgonzo struct sysctl_oid *fclk_node; 356279677Sgonzo char fclk_num[4]; 357279677Sgonzo int i; 358279677Sgonzo 359279677Sgonzo sysctl_ctx_init(&sc->sysctl_tree); 360279677Sgonzo sc->sysctl_tree_top = SYSCTL_ADD_NODE(&sc->sysctl_tree, 361279677Sgonzo SYSCTL_STATIC_CHILDREN(_hw_fpga), OID_AUTO, "fclk", 362279677Sgonzo CTLFLAG_RD, 0, ""); 363279677Sgonzo if (sc->sysctl_tree_top == NULL) { 364279677Sgonzo sysctl_ctx_free(&sc->sysctl_tree); 365279677Sgonzo return (-1); 366279677Sgonzo } 367279677Sgonzo 368279677Sgonzo for (i = 0; i < FCLK_NUM; i++) { 369279677Sgonzo snprintf(fclk_num, sizeof(fclk_num), "%d", i); 370279677Sgonzo fclk_node = SYSCTL_ADD_NODE(&sc->sysctl_tree, 371279677Sgonzo SYSCTL_CHILDREN(sc->sysctl_tree_top), OID_AUTO, fclk_num, 372279677Sgonzo CTLFLAG_RD, 0, ""); 373279677Sgonzo 374279677Sgonzo SYSCTL_ADD_INT(&sc->sysctl_tree, 375279677Sgonzo SYSCTL_CHILDREN(fclk_node), OID_AUTO, 376279677Sgonzo "actual_freq", CTLFLAG_RD, 377279677Sgonzo &fclk_configs[i].actual_frequency, i, 378279677Sgonzo "Actual frequency"); 379279677Sgonzo SYSCTL_ADD_PROC(&sc->sysctl_tree, 380279677Sgonzo SYSCTL_CHILDREN(fclk_node), OID_AUTO, 381279677Sgonzo "freq", CTLFLAG_RW | CTLTYPE_INT, 382279677Sgonzo &fclk_configs[i], i, 383279677Sgonzo zy7_devcfg_fclk_sysctl_freq, 384279677Sgonzo "I", "Configured frequency"); 385279677Sgonzo SYSCTL_ADD_PROC(&sc->sysctl_tree, 386279677Sgonzo SYSCTL_CHILDREN(fclk_node), OID_AUTO, 387279677Sgonzo "source", CTLFLAG_RW | CTLTYPE_STRING, 388279677Sgonzo &fclk_configs[i], i, 389279677Sgonzo zy7_devcfg_fclk_sysctl_source, 390279677Sgonzo "A", "Clock source"); 391279677Sgonzo } 392279677Sgonzo 393279677Sgonzo return (0); 394279677Sgonzo} 395279677Sgonzo 396249997Swkoszek/* Enable programming the PL through PCAP. */ 397249997Swkoszekstatic void 398249997Swkoszekzy7_devcfg_init_hw(struct zy7_devcfg_softc *sc) 399249997Swkoszek{ 400249997Swkoszek 401249997Swkoszek DEVCFG_SC_ASSERT_LOCKED(sc); 402249997Swkoszek 403249997Swkoszek /* Set devcfg control register. */ 404249997Swkoszek WR4(sc, ZY7_DEVCFG_CTRL, 405249997Swkoszek ZY7_DEVCFG_CTRL_PCFG_PROG_B | 406249997Swkoszek ZY7_DEVCFG_CTRL_PCAP_PR | 407249997Swkoszek ZY7_DEVCFG_CTRL_PCAP_MODE | 408249997Swkoszek ZY7_DEVCFG_CTRL_USER_MODE | 409249997Swkoszek ZY7_DEVCFG_CTRL_RESVD_WR11 | 410249997Swkoszek ZY7_DEVCFG_CTRL_SPNIDEN | 411249997Swkoszek ZY7_DEVCFG_CTRL_SPIDEN | 412249997Swkoszek ZY7_DEVCFG_CTRL_NIDEN | 413249997Swkoszek ZY7_DEVCFG_CTRL_DBGEN | 414249997Swkoszek ZY7_DEVCFG_CTRL_DAP_EN_MASK); 415249997Swkoszek 416249997Swkoszek /* Turn off internal PCAP loopback. */ 417249997Swkoszek WR4(sc, ZY7_DEVCFG_MCTRL, RD4(sc, ZY7_DEVCFG_MCTRL) & 418249997Swkoszek ~ZY7_DEVCFG_MCTRL_INT_PCAP_LPBK); 419249997Swkoszek} 420249997Swkoszek 421249997Swkoszek/* Clear previous configuration of the PL by asserting PROG_B. */ 422249997Swkoszekstatic int 423249997Swkoszekzy7_devcfg_reset_pl(struct zy7_devcfg_softc *sc) 424249997Swkoszek{ 425249997Swkoszek uint32_t devcfg_ctl; 426249997Swkoszek int tries, err; 427249997Swkoszek 428249997Swkoszek DEVCFG_SC_ASSERT_LOCKED(sc); 429249997Swkoszek 430249997Swkoszek devcfg_ctl = RD4(sc, ZY7_DEVCFG_CTRL); 431249997Swkoszek 432265690Sian /* Clear sticky bits and set up INIT signal positive edge interrupt. */ 433265690Sian WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL); 434265690Sian WR4(sc, ZY7_DEVCFG_INT_MASK, ~ZY7_DEVCFG_INT_PCFG_INIT_PE); 435265690Sian 436249997Swkoszek /* Deassert PROG_B (active low). */ 437249997Swkoszek devcfg_ctl |= ZY7_DEVCFG_CTRL_PCFG_PROG_B; 438249997Swkoszek WR4(sc, ZY7_DEVCFG_CTRL, devcfg_ctl); 439249997Swkoszek 440265690Sian /* 441265690Sian * Wait for INIT to assert. If it is already asserted, we may not get 442265690Sian * an edge interrupt so cancel it and continue. 443265690Sian */ 444265690Sian if ((RD4(sc, ZY7_DEVCFG_STATUS) & 445265690Sian ZY7_DEVCFG_STATUS_PCFG_INIT) != 0) { 446265690Sian /* Already asserted. Cancel interrupt. */ 447265690Sian WR4(sc, ZY7_DEVCFG_INT_MASK, ~0); 448249997Swkoszek } 449265690Sian else { 450265690Sian /* Wait for positive edge interrupt. */ 451265690Sian err = mtx_sleep(sc, &sc->sc_mtx, PCATCH, "zy7i1", hz); 452265690Sian if (err != 0) 453265690Sian return (err); 454265690Sian } 455265690Sian 456265690Sian /* Reassert PROG_B (active low). */ 457249997Swkoszek devcfg_ctl &= ~ZY7_DEVCFG_CTRL_PCFG_PROG_B; 458249997Swkoszek WR4(sc, ZY7_DEVCFG_CTRL, devcfg_ctl); 459249997Swkoszek 460265690Sian /* Wait for INIT deasserted. This happens almost instantly. */ 461249997Swkoszek tries = 0; 462249997Swkoszek while ((RD4(sc, ZY7_DEVCFG_STATUS) & 463249997Swkoszek ZY7_DEVCFG_STATUS_PCFG_INIT) != 0) { 464249997Swkoszek if (++tries >= 100) 465249997Swkoszek return (EIO); 466249997Swkoszek DELAY(5); 467249997Swkoszek } 468249997Swkoszek 469265690Sian /* Clear sticky bits and set up INIT positive edge interrupt. */ 470249997Swkoszek WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL); 471249997Swkoszek WR4(sc, ZY7_DEVCFG_INT_MASK, ~ZY7_DEVCFG_INT_PCFG_INIT_PE); 472249997Swkoszek 473249997Swkoszek /* Deassert PROG_B again. */ 474249997Swkoszek devcfg_ctl |= ZY7_DEVCFG_CTRL_PCFG_PROG_B; 475249997Swkoszek WR4(sc, ZY7_DEVCFG_CTRL, devcfg_ctl); 476249997Swkoszek 477265690Sian /* 478265690Sian * Wait for INIT asserted indicating FPGA internal initialization 479265690Sian * is complete. 480249997Swkoszek */ 481265690Sian err = mtx_sleep(sc, &sc->sc_mtx, PCATCH, "zy7i2", hz); 482249997Swkoszek if (err != 0) 483249997Swkoszek return (err); 484249997Swkoszek 485249997Swkoszek /* Clear sticky DONE bit in interrupt status. */ 486249997Swkoszek WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL); 487249997Swkoszek 488249997Swkoszek return (0); 489249997Swkoszek} 490249997Swkoszek 491249997Swkoszek/* Callback function for bus_dmamap_load(). */ 492249997Swkoszekstatic void 493249997Swkoszekzy7_dma_cb2(void *arg, bus_dma_segment_t *seg, int nsegs, int error) 494249997Swkoszek{ 495249997Swkoszek if (!error && nsegs == 1) 496249997Swkoszek *(bus_addr_t *)arg = seg[0].ds_addr; 497249997Swkoszek} 498249997Swkoszek 499249997Swkoszekstatic int 500249997Swkoszekzy7_devcfg_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 501249997Swkoszek{ 502249997Swkoszek struct zy7_devcfg_softc *sc = dev->si_drv1; 503249997Swkoszek int err; 504249997Swkoszek 505249997Swkoszek DEVCFG_SC_LOCK(sc); 506249997Swkoszek if (sc->is_open) { 507249997Swkoszek DEVCFG_SC_UNLOCK(sc); 508249997Swkoszek return (EBUSY); 509249997Swkoszek } 510249997Swkoszek 511249997Swkoszek sc->dma_map = NULL; 512249997Swkoszek err = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 4, 0, 513249997Swkoszek BUS_SPACE_MAXADDR_32BIT, 514249997Swkoszek BUS_SPACE_MAXADDR, 515249997Swkoszek NULL, NULL, 516249997Swkoszek PAGE_SIZE, 517249997Swkoszek 1, 518249997Swkoszek PAGE_SIZE, 519249997Swkoszek 0, 520249997Swkoszek busdma_lock_mutex, 521249997Swkoszek &sc->sc_mtx, 522249997Swkoszek &sc->dma_tag); 523249997Swkoszek if (err) { 524249997Swkoszek DEVCFG_SC_UNLOCK(sc); 525249997Swkoszek return (err); 526249997Swkoszek } 527249997Swkoszek 528249997Swkoszek sc->is_open = 1; 529249997Swkoszek DEVCFG_SC_UNLOCK(sc); 530249997Swkoszek return (0); 531249997Swkoszek} 532249997Swkoszek 533249997Swkoszekstatic int 534249997Swkoszekzy7_devcfg_write(struct cdev *dev, struct uio *uio, int ioflag) 535249997Swkoszek{ 536249997Swkoszek struct zy7_devcfg_softc *sc = dev->si_drv1; 537249997Swkoszek void *dma_mem; 538249997Swkoszek bus_addr_t dma_physaddr; 539249997Swkoszek int segsz, err; 540249997Swkoszek 541249997Swkoszek DEVCFG_SC_LOCK(sc); 542249997Swkoszek 543249997Swkoszek /* First write? Reset PL. */ 544249997Swkoszek if (uio->uio_offset == 0 && uio->uio_resid > 0) { 545249997Swkoszek zy7_devcfg_init_hw(sc); 546249997Swkoszek zy7_slcr_preload_pl(); 547249997Swkoszek err = zy7_devcfg_reset_pl(sc); 548249997Swkoszek if (err != 0) { 549249997Swkoszek DEVCFG_SC_UNLOCK(sc); 550249997Swkoszek return (err); 551249997Swkoszek } 552249997Swkoszek } 553249997Swkoszek 554249997Swkoszek /* Allocate dma memory and load. */ 555249997Swkoszek err = bus_dmamem_alloc(sc->dma_tag, &dma_mem, BUS_DMA_NOWAIT, 556249997Swkoszek &sc->dma_map); 557249997Swkoszek if (err != 0) { 558249997Swkoszek DEVCFG_SC_UNLOCK(sc); 559249997Swkoszek return (err); 560249997Swkoszek } 561249997Swkoszek err = bus_dmamap_load(sc->dma_tag, sc->dma_map, dma_mem, PAGE_SIZE, 562249997Swkoszek zy7_dma_cb2, &dma_physaddr, 0); 563249997Swkoszek if (err != 0) { 564249997Swkoszek bus_dmamem_free(sc->dma_tag, dma_mem, sc->dma_map); 565249997Swkoszek DEVCFG_SC_UNLOCK(sc); 566249997Swkoszek return (err); 567249997Swkoszek } 568249997Swkoszek 569249997Swkoszek while (uio->uio_resid > 0) { 570249997Swkoszek /* If DONE signal has been set, we shouldn't write anymore. */ 571249997Swkoszek if ((RD4(sc, ZY7_DEVCFG_INT_STATUS) & 572249997Swkoszek ZY7_DEVCFG_INT_PCFG_DONE) != 0) { 573249997Swkoszek err = EIO; 574249997Swkoszek break; 575249997Swkoszek } 576249997Swkoszek 577249997Swkoszek /* uiomove the data from user buffer to our dma map. */ 578249997Swkoszek segsz = MIN(PAGE_SIZE, uio->uio_resid); 579265690Sian DEVCFG_SC_UNLOCK(sc); 580249997Swkoszek err = uiomove(dma_mem, segsz, uio); 581265690Sian DEVCFG_SC_LOCK(sc); 582249997Swkoszek if (err != 0) 583249997Swkoszek break; 584249997Swkoszek 585249997Swkoszek /* Flush the cache to memory. */ 586249997Swkoszek bus_dmamap_sync(sc->dma_tag, sc->dma_map, 587249997Swkoszek BUS_DMASYNC_PREWRITE); 588249997Swkoszek 589249997Swkoszek /* Program devcfg's DMA engine. The ordering of these 590249997Swkoszek * register writes is critical. 591249997Swkoszek */ 592249997Swkoszek if (uio->uio_resid > segsz) 593249997Swkoszek WR4(sc, ZY7_DEVCFG_DMA_SRC_ADDR, 594249997Swkoszek (uint32_t) dma_physaddr); 595249997Swkoszek else 596249997Swkoszek WR4(sc, ZY7_DEVCFG_DMA_SRC_ADDR, 597249997Swkoszek (uint32_t) dma_physaddr | 598249997Swkoszek ZY7_DEVCFG_DMA_ADDR_WAIT_PCAP); 599249997Swkoszek WR4(sc, ZY7_DEVCFG_DMA_DST_ADDR, ZY7_DEVCFG_DMA_ADDR_ILLEGAL); 600249997Swkoszek WR4(sc, ZY7_DEVCFG_DMA_SRC_LEN, (segsz+3)/4); 601249997Swkoszek WR4(sc, ZY7_DEVCFG_DMA_DST_LEN, 0); 602249997Swkoszek 603249997Swkoszek /* Now clear done bit and set up DMA done interrupt. */ 604249997Swkoszek WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL); 605249997Swkoszek WR4(sc, ZY7_DEVCFG_INT_MASK, ~ZY7_DEVCFG_INT_DMA_DONE); 606249997Swkoszek 607249997Swkoszek /* Wait for DMA done interrupt. */ 608249997Swkoszek err = mtx_sleep(sc->dma_map, &sc->sc_mtx, PCATCH, 609249997Swkoszek "zy7dma", hz); 610249997Swkoszek if (err != 0) 611249997Swkoszek break; 612249997Swkoszek 613249997Swkoszek bus_dmamap_sync(sc->dma_tag, sc->dma_map, 614249997Swkoszek BUS_DMASYNC_POSTWRITE); 615249997Swkoszek 616249997Swkoszek /* Check DONE signal. */ 617249997Swkoszek if ((RD4(sc, ZY7_DEVCFG_INT_STATUS) & 618249997Swkoszek ZY7_DEVCFG_INT_PCFG_DONE) != 0) 619249997Swkoszek zy7_slcr_postload_pl(zy7_en_level_shifters); 620249997Swkoszek } 621249997Swkoszek 622249997Swkoszek bus_dmamap_unload(sc->dma_tag, sc->dma_map); 623249997Swkoszek bus_dmamem_free(sc->dma_tag, dma_mem, sc->dma_map); 624249997Swkoszek DEVCFG_SC_UNLOCK(sc); 625249997Swkoszek return (err); 626249997Swkoszek} 627249997Swkoszek 628249997Swkoszekstatic int 629249997Swkoszekzy7_devcfg_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 630249997Swkoszek{ 631249997Swkoszek struct zy7_devcfg_softc *sc = dev->si_drv1; 632249997Swkoszek 633249997Swkoszek DEVCFG_SC_LOCK(sc); 634249997Swkoszek sc->is_open = 0; 635249997Swkoszek bus_dma_tag_destroy(sc->dma_tag); 636249997Swkoszek DEVCFG_SC_UNLOCK(sc); 637249997Swkoszek 638279677Sgonzo zy7_slcr_postload_pl(zy7_en_level_shifters); 639279677Sgonzo 640249997Swkoszek return (0); 641249997Swkoszek} 642249997Swkoszek 643249997Swkoszekstatic void 644249997Swkoszekzy7_devcfg_intr(void *arg) 645249997Swkoszek{ 646249997Swkoszek struct zy7_devcfg_softc *sc = (struct zy7_devcfg_softc *)arg; 647249997Swkoszek uint32_t istatus, imask; 648249997Swkoszek 649249997Swkoszek DEVCFG_SC_LOCK(sc); 650249997Swkoszek 651249997Swkoszek istatus = RD4(sc, ZY7_DEVCFG_INT_STATUS); 652249997Swkoszek imask = ~RD4(sc, ZY7_DEVCFG_INT_MASK); 653249997Swkoszek 654249997Swkoszek /* Turn interrupt off. */ 655249997Swkoszek WR4(sc, ZY7_DEVCFG_INT_MASK, ~0); 656249997Swkoszek 657249997Swkoszek if ((istatus & imask) == 0) { 658249997Swkoszek DEVCFG_SC_UNLOCK(sc); 659249997Swkoszek return; 660249997Swkoszek } 661249997Swkoszek 662249997Swkoszek /* DMA done? */ 663249997Swkoszek if ((istatus & ZY7_DEVCFG_INT_DMA_DONE) != 0) 664249997Swkoszek wakeup(sc->dma_map); 665249997Swkoszek 666249997Swkoszek /* INIT_B positive edge? */ 667249997Swkoszek if ((istatus & ZY7_DEVCFG_INT_PCFG_INIT_PE) != 0) 668249997Swkoszek wakeup(sc); 669249997Swkoszek 670249997Swkoszek DEVCFG_SC_UNLOCK(sc); 671249997Swkoszek} 672249997Swkoszek 673249997Swkoszek/* zy7_devcfg_sysctl_pl_done() returns status of the PL_DONE signal. 674249997Swkoszek */ 675249997Swkoszekstatic int 676249997Swkoszekzy7_devcfg_sysctl_pl_done(SYSCTL_HANDLER_ARGS) 677249997Swkoszek{ 678249997Swkoszek struct zy7_devcfg_softc *sc = zy7_devcfg_softc_p; 679249997Swkoszek int pl_done = 0; 680249997Swkoszek 681249997Swkoszek if (sc) { 682249997Swkoszek DEVCFG_SC_LOCK(sc); 683249997Swkoszek 684249997Swkoszek /* PCFG_DONE bit is sticky. Clear it before checking it. */ 685249997Swkoszek WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_PCFG_DONE); 686249997Swkoszek pl_done = ((RD4(sc, ZY7_DEVCFG_INT_STATUS) & 687249997Swkoszek ZY7_DEVCFG_INT_PCFG_DONE) != 0); 688249997Swkoszek 689249997Swkoszek DEVCFG_SC_UNLOCK(sc); 690249997Swkoszek } 691249997Swkoszek return (sysctl_handle_int(oidp, &pl_done, 0, req)); 692249997Swkoszek} 693249997Swkoszek 694249997Swkoszekstatic int 695249997Swkoszekzy7_devcfg_probe(device_t dev) 696249997Swkoszek{ 697261410Sian 698261410Sian if (!ofw_bus_status_okay(dev)) 699261410Sian return (ENXIO); 700261410Sian 701249997Swkoszek if (!ofw_bus_is_compatible(dev, "xlnx,zy7_devcfg")) 702249997Swkoszek return (ENXIO); 703249997Swkoszek 704249997Swkoszek device_set_desc(dev, "Zynq devcfg block"); 705249997Swkoszek return (0); 706249997Swkoszek} 707249997Swkoszek 708249997Swkoszekstatic int zy7_devcfg_detach(device_t dev); 709249997Swkoszek 710249997Swkoszekstatic int 711249997Swkoszekzy7_devcfg_attach(device_t dev) 712249997Swkoszek{ 713249997Swkoszek struct zy7_devcfg_softc *sc = device_get_softc(dev); 714279677Sgonzo int i; 715249997Swkoszek int rid, err; 716249997Swkoszek 717249997Swkoszek /* Allow only one attach. */ 718249997Swkoszek if (zy7_devcfg_softc_p != NULL) 719249997Swkoszek return (ENXIO); 720249997Swkoszek 721249997Swkoszek sc->dev = dev; 722249997Swkoszek 723249997Swkoszek DEVCFG_SC_LOCK_INIT(sc); 724249997Swkoszek 725249997Swkoszek /* Get memory resource. */ 726249997Swkoszek rid = 0; 727249997Swkoszek sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 728249997Swkoszek RF_ACTIVE); 729249997Swkoszek if (sc->mem_res == NULL) { 730249997Swkoszek device_printf(dev, "could not allocate memory resources.\n"); 731249997Swkoszek zy7_devcfg_detach(dev); 732249997Swkoszek return (ENOMEM); 733249997Swkoszek } 734249997Swkoszek 735249997Swkoszek /* Allocate IRQ. */ 736249997Swkoszek rid = 0; 737249997Swkoszek sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 738249997Swkoszek RF_ACTIVE); 739249997Swkoszek if (sc->irq_res == NULL) { 740249997Swkoszek device_printf(dev, "cannot allocate IRQ\n"); 741249997Swkoszek zy7_devcfg_detach(dev); 742249997Swkoszek return (ENOMEM); 743249997Swkoszek } 744249997Swkoszek 745249997Swkoszek /* Activate the interrupt. */ 746249997Swkoszek err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 747249997Swkoszek NULL, zy7_devcfg_intr, sc, &sc->intrhandle); 748249997Swkoszek if (err) { 749249997Swkoszek device_printf(dev, "cannot setup IRQ\n"); 750249997Swkoszek zy7_devcfg_detach(dev); 751249997Swkoszek return (err); 752249997Swkoszek } 753249997Swkoszek 754249997Swkoszek /* Create /dev/devcfg */ 755249997Swkoszek sc->sc_ctl_dev = make_dev(&zy7_devcfg_cdevsw, 0, 756249997Swkoszek UID_ROOT, GID_WHEEL, 0600, "devcfg"); 757249997Swkoszek if (sc->sc_ctl_dev == NULL) { 758249997Swkoszek device_printf(dev, "failed to create /dev/devcfg"); 759249997Swkoszek zy7_devcfg_detach(dev); 760249997Swkoszek return (ENXIO); 761249997Swkoszek } 762249997Swkoszek sc->sc_ctl_dev->si_drv1 = sc; 763249997Swkoszek 764249997Swkoszek zy7_devcfg_softc_p = sc; 765249997Swkoszek 766249997Swkoszek /* Unlock devcfg registers. */ 767249997Swkoszek WR4(sc, ZY7_DEVCFG_UNLOCK, ZY7_DEVCFG_UNLOCK_MAGIC); 768249997Swkoszek 769249997Swkoszek /* Make sure interrupts are completely disabled. */ 770249997Swkoszek WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL); 771249997Swkoszek WR4(sc, ZY7_DEVCFG_INT_MASK, 0xffffffff); 772249997Swkoszek 773249997Swkoszek /* Get PS_VERS for SYSCTL. */ 774249997Swkoszek zy7_ps_vers = (RD4(sc, ZY7_DEVCFG_MCTRL) & 775249997Swkoszek ZY7_DEVCFG_MCTRL_PS_VERS_MASK) >> 776249997Swkoszek ZY7_DEVCFG_MCTRL_PS_VERS_SHIFT; 777249997Swkoszek 778279677Sgonzo for (i = 0; i < FCLK_NUM; i++) { 779279677Sgonzo fclk_configs[i].source = zy7_pl_fclk_get_source(i); 780279677Sgonzo fclk_configs[i].actual_frequency = 781279677Sgonzo zy7_pl_fclk_enabled(i) ? zy7_pl_fclk_get_freq(i) : 0; 782279677Sgonzo /* Initially assume actual frequency is the configure one */ 783279677Sgonzo fclk_configs[i].frequency = fclk_configs[i].actual_frequency; 784279677Sgonzo } 785279677Sgonzo 786279677Sgonzo if (zy7_devcfg_init_fclk_sysctl(sc) < 0) 787279677Sgonzo device_printf(dev, "failed to initialized sysctl tree\n"); 788279677Sgonzo 789249997Swkoszek return (0); 790249997Swkoszek} 791249997Swkoszek 792249997Swkoszekstatic int 793249997Swkoszekzy7_devcfg_detach(device_t dev) 794249997Swkoszek{ 795249997Swkoszek struct zy7_devcfg_softc *sc = device_get_softc(dev); 796249997Swkoszek 797279677Sgonzo if (sc->sysctl_tree_top != NULL) { 798279677Sgonzo sysctl_ctx_free(&sc->sysctl_tree); 799279677Sgonzo sc->sysctl_tree_top = NULL; 800279677Sgonzo } 801279677Sgonzo 802249997Swkoszek if (device_is_attached(dev)) 803249997Swkoszek bus_generic_detach(dev); 804249997Swkoszek 805249997Swkoszek /* Get rid of /dev/devcfg0. */ 806249997Swkoszek if (sc->sc_ctl_dev != NULL) 807249997Swkoszek destroy_dev(sc->sc_ctl_dev); 808249997Swkoszek 809249997Swkoszek /* Teardown and release interrupt. */ 810249997Swkoszek if (sc->irq_res != NULL) { 811249997Swkoszek if (sc->intrhandle) 812249997Swkoszek bus_teardown_intr(dev, sc->irq_res, sc->intrhandle); 813249997Swkoszek bus_release_resource(dev, SYS_RES_IRQ, 814249997Swkoszek rman_get_rid(sc->irq_res), sc->irq_res); 815249997Swkoszek } 816249997Swkoszek 817249997Swkoszek /* Release memory resource. */ 818249997Swkoszek if (sc->mem_res != NULL) 819249997Swkoszek bus_release_resource(dev, SYS_RES_MEMORY, 820249997Swkoszek rman_get_rid(sc->mem_res), sc->mem_res); 821249997Swkoszek 822249997Swkoszek zy7_devcfg_softc_p = NULL; 823249997Swkoszek 824249997Swkoszek DEVCFG_SC_LOCK_DESTROY(sc); 825249997Swkoszek 826249997Swkoszek return (0); 827249997Swkoszek} 828249997Swkoszek 829249997Swkoszekstatic device_method_t zy7_devcfg_methods[] = { 830249997Swkoszek /* device_if */ 831249997Swkoszek DEVMETHOD(device_probe, zy7_devcfg_probe), 832249997Swkoszek DEVMETHOD(device_attach, zy7_devcfg_attach), 833249997Swkoszek DEVMETHOD(device_detach, zy7_devcfg_detach), 834249997Swkoszek 835249997Swkoszek DEVMETHOD_END 836249997Swkoszek}; 837249997Swkoszek 838249997Swkoszekstatic driver_t zy7_devcfg_driver = { 839249997Swkoszek "zy7_devcfg", 840249997Swkoszek zy7_devcfg_methods, 841249997Swkoszek sizeof(struct zy7_devcfg_softc), 842249997Swkoszek}; 843249997Swkoszekstatic devclass_t zy7_devcfg_devclass; 844249997Swkoszek 845249997SwkoszekDRIVER_MODULE(zy7_devcfg, simplebus, zy7_devcfg_driver, zy7_devcfg_devclass, \ 846249997Swkoszek 0, 0); 847249997SwkoszekMODULE_DEPEND(zy7_devcfg, zy7_slcr, 1, 1, 1); 848