zy7_devcfg.c revision 330897
1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2013 Thomas Skibo 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD: stable/11/sys/arm/xilinx/zy7_devcfg.c 330897 2018-03-14 03:19:51Z eadler $ 29 */ 30 31/* 32 * Zynq-7000 Devcfg driver. This allows programming the PL (FPGA) section 33 * of Zynq. 34 * 35 * Reference: Zynq-7000 All Programmable SoC Technical Reference Manual. 36 * (v1.4) November 16, 2012. Xilinx doc UG585. PL Configuration is 37 * covered in section 6.4.5. 38 */ 39 40#include <sys/cdefs.h> 41__FBSDID("$FreeBSD: stable/11/sys/arm/xilinx/zy7_devcfg.c 330897 2018-03-14 03:19:51Z eadler $"); 42 43#include <sys/param.h> 44#include <sys/systm.h> 45#include <sys/conf.h> 46#include <sys/kernel.h> 47#include <sys/module.h> 48#include <sys/sysctl.h> 49#include <sys/lock.h> 50#include <sys/mutex.h> 51#include <sys/resource.h> 52#include <sys/rman.h> 53#include <sys/uio.h> 54 55#include <machine/bus.h> 56#include <machine/resource.h> 57#include <machine/stdarg.h> 58 59#include <dev/fdt/fdt_common.h> 60#include <dev/ofw/ofw_bus.h> 61#include <dev/ofw/ofw_bus_subr.h> 62 63#include <arm/xilinx/zy7_slcr.h> 64 65struct zy7_devcfg_softc { 66 device_t dev; 67 struct mtx sc_mtx; 68 struct resource *mem_res; 69 struct resource *irq_res; 70 struct cdev *sc_ctl_dev; 71 void *intrhandle; 72 73 bus_dma_tag_t dma_tag; 74 bus_dmamap_t dma_map; 75 76 int is_open; 77 78 struct sysctl_ctx_list sysctl_tree; 79 struct sysctl_oid *sysctl_tree_top; 80}; 81 82static struct zy7_devcfg_softc *zy7_devcfg_softc_p; 83 84#define FCLK_NUM 4 85 86struct zy7_fclk_config { 87 int source; 88 int frequency; 89 int actual_frequency; 90}; 91 92static struct zy7_fclk_config fclk_configs[FCLK_NUM]; 93 94#define DEVCFG_SC_LOCK(sc) mtx_lock(&(sc)->sc_mtx) 95#define DEVCFG_SC_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) 96#define DEVCFG_SC_LOCK_INIT(sc) \ 97 mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), \ 98 "zy7_devcfg", MTX_DEF) 99#define DEVCFG_SC_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_mtx); 100#define DEVCFG_SC_ASSERT_LOCKED(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED); 101 102#define RD4(sc, off) (bus_read_4((sc)->mem_res, (off))) 103#define WR4(sc, off, val) (bus_write_4((sc)->mem_res, (off), (val))) 104 105SYSCTL_NODE(_hw, OID_AUTO, fpga, CTLFLAG_RD, 0, \ 106 "Xilinx Zynq-7000 PL (FPGA) section"); 107 108static int zy7_devcfg_sysctl_pl_done(SYSCTL_HANDLER_ARGS); 109SYSCTL_PROC(_hw_fpga, OID_AUTO, pl_done, CTLTYPE_INT | CTLFLAG_RD, NULL, 0, 110 zy7_devcfg_sysctl_pl_done, "I", "PL section config DONE signal"); 111 112static int zy7_en_level_shifters = 1; 113SYSCTL_INT(_hw_fpga, OID_AUTO, en_level_shifters, CTLFLAG_RW, 114 &zy7_en_level_shifters, 0, 115 "Enable PS-PL level shifters after device config"); 116 117static int zy7_ps_vers = 0; 118SYSCTL_INT(_hw, OID_AUTO, ps_vers, CTLFLAG_RD, &zy7_ps_vers, 0, 119 "Zynq-7000 PS version"); 120 121static int zy7_devcfg_fclk_sysctl_level_shifters(SYSCTL_HANDLER_ARGS); 122SYSCTL_PROC(_hw_fpga, OID_AUTO, level_shifters, 123 CTLFLAG_RW | CTLTYPE_INT, 124 NULL, 0, zy7_devcfg_fclk_sysctl_level_shifters, 125 "I", "Enable/disable level shifters"); 126 127/* cdev entry points. */ 128static int zy7_devcfg_open(struct cdev *, int, int, struct thread *); 129static int zy7_devcfg_write(struct cdev *, struct uio *, int); 130static int zy7_devcfg_close(struct cdev *, int, int, struct thread *); 131 132struct cdevsw zy7_devcfg_cdevsw = { 133 .d_version = D_VERSION, 134 .d_open = zy7_devcfg_open, 135 .d_write = zy7_devcfg_write, 136 .d_close = zy7_devcfg_close, 137 .d_name = "devcfg", 138}; 139 140/* Devcfg block registers. */ 141#define ZY7_DEVCFG_CTRL 0x0000 142#define ZY7_DEVCFG_CTRL_FORCE_RST (1<<31) 143#define ZY7_DEVCFG_CTRL_PCFG_PROG_B (1<<30) 144#define ZY7_DEVCFG_CTRL_PCFG_POR_CNT_4K (1<<29) 145#define ZY7_DEVCFG_CTRL_PCAP_PR (1<<27) 146#define ZY7_DEVCFG_CTRL_PCAP_MODE (1<<26) 147#define ZY7_DEVCFG_CTRL_QTR_PCAP_RATE_EN (1<<25) 148#define ZY7_DEVCFG_CTRL_MULTIBOOT_EN (1<<24) 149#define ZY7_DEVCFG_CTRL_JTAG_CHAIN_DIS (1<<23) 150#define ZY7_DEVCFG_CTRL_USER_MODE (1<<15) 151#define ZY7_DEVCFG_CTRL_RESVD_WR11 (3<<13) /* always write 11 */ 152#define ZY7_DEVCFG_CTRL_PCFG_AES_FUSE (1<<12) 153#define ZY7_DEVCFG_CTRL_PCFG_AES_EN_MASK (7<<9) /* all 1's or 0's */ 154#define ZY7_DEVCFG_CTRL_SEU_EN (1<<8) 155#define ZY7_DEVCFG_CTRL_SEC_EN (1<<7) 156#define ZY7_DEVCFG_CTRL_SPNIDEN (1<<6) 157#define ZY7_DEVCFG_CTRL_SPIDEN (1<<5) 158#define ZY7_DEVCFG_CTRL_NIDEN (1<<4) 159#define ZY7_DEVCFG_CTRL_DBGEN (1<<3) 160#define ZY7_DEVCFG_CTRL_DAP_EN_MASK (7<<0) /* all 1's to enable */ 161 162#define ZY7_DEVCFG_LOCK 0x004 163#define ZY7_DEVCFG_LOCK_AES_FUSE_LOCK (1<<4) 164#define ZY7_DEVCFG_LOCK_AES_EN (1<<3) 165#define ZY7_DEVCFG_LOCK_SEU_LOCK (1<<2) 166#define ZY7_DEVCFG_LOCK_SEC_LOCK (1<<1) 167#define ZY7_DEVCFG_LOCK_DBG_LOCK (1<<0) 168 169#define ZY7_DEVCFG_CFG 0x008 170#define ZY7_DEVCFG_CFG_RFIFO_TH_MASK (3<<10) 171#define ZY7_DEVCFG_CFG_WFIFO_TH_MASK (3<<8) 172#define ZY7_DEVCFG_CFG_RCLK_EDGE (1<<7) 173#define ZY7_DEVCFG_CFG_WCLK_EDGE (1<<6) 174#define ZY7_DEVCFG_CFG_DIS_SRC_INC (1<<5) 175#define ZY7_DEVCFG_CFG_DIS_DST_INC (1<<4) 176 177#define ZY7_DEVCFG_INT_STATUS 0x00C 178#define ZY7_DEVCFG_INT_MASK 0x010 179#define ZY7_DEVCFG_INT_PSS_GTS_USR_B (1<<31) 180#define ZY7_DEVCFG_INT_PSS_FST_CFG_B (1<<30) 181#define ZY7_DEVCFG_INT_PSS_GPWRDWN_B (1<<29) 182#define ZY7_DEVCFG_INT_PSS_GTS_CFG_B (1<<28) 183#define ZY7_DEVCFG_INT_CFG_RESET_B (1<<27) 184#define ZY7_DEVCFG_INT_AXI_WTO (1<<23) /* axi write timeout */ 185#define ZY7_DEVCFG_INT_AXI_WERR (1<<22) /* axi write err */ 186#define ZY7_DEVCFG_INT_AXI_RTO (1<<21) /* axi read timeout */ 187#define ZY7_DEVCFG_INT_AXI_RERR (1<<20) /* axi read err */ 188#define ZY7_DEVCFG_INT_RX_FIFO_OV (1<<18) /* rx fifo overflow */ 189#define ZY7_DEVCFG_INT_WR_FIFO_LVL (1<<17) /* wr fifo < level */ 190#define ZY7_DEVCFG_INT_RD_FIFO_LVL (1<<16) /* rd fifo >= level */ 191#define ZY7_DEVCFG_INT_DMA_CMD_ERR (1<<15) 192#define ZY7_DEVCFG_INT_DMA_Q_OV (1<<14) 193#define ZY7_DEVCFG_INT_DMA_DONE (1<<13) 194#define ZY7_DEVCFG_INT_DMA_PCAP_DONE (1<<12) 195#define ZY7_DEVCFG_INT_P2D_LEN_ERR (1<<11) 196#define ZY7_DEVCFG_INT_PCFG_HMAC_ERR (1<<6) 197#define ZY7_DEVCFG_INT_PCFG_SEU_ERR (1<<5) 198#define ZY7_DEVCFG_INT_PCFG_POR_B (1<<4) 199#define ZY7_DEVCFG_INT_PCFG_CFG_RST (1<<3) 200#define ZY7_DEVCFG_INT_PCFG_DONE (1<<2) 201#define ZY7_DEVCFG_INT_PCFG_INIT_PE (1<<1) 202#define ZY7_DEVCFG_INT_PCFG_INIT_NE (1<<0) 203#define ZY7_DEVCFG_INT_ERRORS 0x00f0f860 204#define ZY7_DEVCFG_INT_ALL 0xf8f7f87f 205 206#define ZY7_DEVCFG_STATUS 0x014 207#define ZY7_DEVCFG_STATUS_DMA_CMD_Q_F (1<<31) /* cmd queue full */ 208#define ZY7_DEVCFG_STATUS_DMA_CMD_Q_E (1<<30) /* cmd queue empty */ 209#define ZY7_DEVCFG_STATUS_DONE_COUNT_MASK (3<<28) 210#define ZY7_DEVCFG_STATUS_DONE_COUNT_SHIFT 28 211#define ZY7_DEVCFG_STATUS_RX_FIFO_LVL_MASK (0x1f<<20) 212#define ZY7_DEVCFG_STATUS_RX_FIFO_LVL_SHIFT 20 213#define ZY7_DEVCFG_STATUS_TX_FIFO_LVL_MASK (0x7f<<12) 214#define ZY7_DEVCFG_STATUS_TX_FIFO_LVL_SHIFT 12 215#define ZY7_DEVCFG_STATUS_PSS_GTS_USR_B (1<<11) 216#define ZY7_DEVCFG_STATUS_PSS_FST_CFG_B (1<<10) 217#define ZY7_DEVCFG_STATUS_PSS_GPWRDWN_B (1<<9) 218#define ZY7_DEVCFG_STATUS_PSS_GTS_CFG_B (1<<8) 219#define ZY7_DEVCFG_STATUS_ILL_APB_ACCE (1<<6) 220#define ZY7_DEVCFG_STATUS_PSS_CFG_RESET_B (1<<5) 221#define ZY7_DEVCFG_STATUS_PCFG_INIT (1<<4) 222#define ZY7_DEVCFG_STATUS_EFUSE_BBRAM_KEY_DIS (1<<3) 223#define ZY7_DEVCFG_STATUS_EFUSE_SEC_EN (1<<2) 224#define ZY7_DEVCFG_STATUS_EFUSE_JTAG_DIS (1<<1) 225 226#define ZY7_DEVCFG_DMA_SRC_ADDR 0x018 227#define ZY7_DEVCFG_DMA_DST_ADDR 0x01c 228#define ZY7_DEVCFG_DMA_ADDR_WAIT_PCAP 1 229#define ZY7_DEVCFG_DMA_ADDR_ILLEGAL 0xffffffff 230 231#define ZY7_DEVCFG_DMA_SRC_LEN 0x020 /* in 4-byte words. */ 232#define ZY7_DEVCFG_DMA_SRC_LEN_MAX 0x7ffffff 233#define ZY7_DEVCFG_DMA_DST_LEN 0x024 234#define ZY7_DEVCFG_ROM_SHADOW 0x028 235#define ZY7_DEVCFG_MULTIBOOT_ADDR 0x02c 236#define ZY7_DEVCFG_SW_ID 0x030 237#define ZY7_DEVCFG_UNLOCK 0x034 238#define ZY7_DEVCFG_UNLOCK_MAGIC 0x757bdf0d 239#define ZY7_DEVCFG_MCTRL 0x080 240#define ZY7_DEVCFG_MCTRL_PS_VERS_MASK (0xf<<28) 241#define ZY7_DEVCFG_MCTRL_PS_VERS_SHIFT 28 242#define ZY7_DEVCFG_MCTRL_PCFG_POR_B (1<<8) 243#define ZY7_DEVCFG_MCTRL_INT_PCAP_LPBK (1<<4) 244#define ZY7_DEVCFG_XADCIF_CFG 0x100 245#define ZY7_DEVCFG_XADCIF_INT_STAT 0x104 246#define ZY7_DEVCFG_XADCIF_INT_MASK 0x108 247#define ZY7_DEVCFG_XADCIF_MSTS 0x10c 248#define ZY7_DEVCFG_XADCIF_CMD_FIFO 0x110 249#define ZY7_DEVCFG_XADCIF_RD_FIFO 0x114 250#define ZY7_DEVCFG_XADCIF_MCTL 0x118 251 252static int 253zy7_devcfg_fclk_sysctl_source(SYSCTL_HANDLER_ARGS) 254{ 255 char buf[4]; 256 struct zy7_fclk_config *cfg; 257 int unit; 258 int error; 259 260 cfg = arg1; 261 unit = arg2; 262 263 switch (cfg->source) { 264 case ZY7_PL_FCLK_SRC_IO: 265 case ZY7_PL_FCLK_SRC_IO_ALT: 266 strncpy(buf, "IO", sizeof(buf)); 267 break; 268 case ZY7_PL_FCLK_SRC_DDR: 269 strncpy(buf, "DDR", sizeof(buf)); 270 break; 271 case ZY7_PL_FCLK_SRC_ARM: 272 strncpy(buf, "ARM", sizeof(buf)); 273 break; 274 default: 275 strncpy(buf, "???", sizeof(buf)); 276 break; 277 } 278 279 error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 280 if (error != 0 || req->newptr == NULL) 281 return (error); 282 283 if (strcasecmp(buf, "io") == 0) 284 cfg->source = ZY7_PL_FCLK_SRC_IO; 285 else if (strcasecmp(buf, "ddr") == 0) 286 cfg->source = ZY7_PL_FCLK_SRC_DDR; 287 else if (strcasecmp(buf, "arm") == 0) 288 cfg->source = ZY7_PL_FCLK_SRC_ARM; 289 else 290 return (EINVAL); 291 292 zy7_pl_fclk_set_source(unit, cfg->source); 293 if (cfg->frequency > 0) 294 cfg->actual_frequency = zy7_pl_fclk_get_freq(unit); 295 296 return (0); 297} 298 299static int 300zy7_devcfg_fclk_sysctl_freq(SYSCTL_HANDLER_ARGS) 301{ 302 struct zy7_fclk_config *cfg; 303 int unit; 304 int error; 305 int freq; 306 int new_actual_freq; 307 308 cfg = arg1; 309 unit = arg2; 310 311 freq = cfg->frequency; 312 313 error = sysctl_handle_int(oidp, &freq, 0, req); 314 if (error != 0 || req->newptr == NULL) 315 return (error); 316 317 if (freq > 0) { 318 new_actual_freq = zy7_pl_fclk_set_freq(unit, freq); 319 if (new_actual_freq < 0) 320 return (EINVAL); 321 if (!zy7_pl_fclk_enabled(unit)) 322 zy7_pl_fclk_enable(unit); 323 } 324 else { 325 zy7_pl_fclk_disable(unit); 326 new_actual_freq = 0; 327 } 328 329 cfg->frequency = freq; 330 cfg->actual_frequency = new_actual_freq; 331 332 return (0); 333} 334 335static int 336zy7_devcfg_fclk_sysctl_level_shifters(SYSCTL_HANDLER_ARGS) 337{ 338 int error, enabled; 339 340 enabled = zy7_pl_level_shifters_enabled(); 341 342 error = sysctl_handle_int(oidp, &enabled, 0, req); 343 if (error != 0 || req->newptr == NULL) 344 return (error); 345 346 if (enabled) 347 zy7_pl_level_shifters_enable(); 348 else 349 zy7_pl_level_shifters_disable(); 350 351 return (0); 352} 353 354static int 355zy7_devcfg_init_fclk_sysctl(struct zy7_devcfg_softc *sc) 356{ 357 struct sysctl_oid *fclk_node; 358 char fclk_num[4]; 359 int i; 360 361 sysctl_ctx_init(&sc->sysctl_tree); 362 sc->sysctl_tree_top = SYSCTL_ADD_NODE(&sc->sysctl_tree, 363 SYSCTL_STATIC_CHILDREN(_hw_fpga), OID_AUTO, "fclk", 364 CTLFLAG_RD, 0, ""); 365 if (sc->sysctl_tree_top == NULL) { 366 sysctl_ctx_free(&sc->sysctl_tree); 367 return (-1); 368 } 369 370 for (i = 0; i < FCLK_NUM; i++) { 371 snprintf(fclk_num, sizeof(fclk_num), "%d", i); 372 fclk_node = SYSCTL_ADD_NODE(&sc->sysctl_tree, 373 SYSCTL_CHILDREN(sc->sysctl_tree_top), OID_AUTO, fclk_num, 374 CTLFLAG_RD, 0, ""); 375 376 SYSCTL_ADD_INT(&sc->sysctl_tree, 377 SYSCTL_CHILDREN(fclk_node), OID_AUTO, 378 "actual_freq", CTLFLAG_RD, 379 &fclk_configs[i].actual_frequency, i, 380 "Actual frequency"); 381 SYSCTL_ADD_PROC(&sc->sysctl_tree, 382 SYSCTL_CHILDREN(fclk_node), OID_AUTO, 383 "freq", CTLFLAG_RW | CTLTYPE_INT, 384 &fclk_configs[i], i, 385 zy7_devcfg_fclk_sysctl_freq, 386 "I", "Configured frequency"); 387 SYSCTL_ADD_PROC(&sc->sysctl_tree, 388 SYSCTL_CHILDREN(fclk_node), OID_AUTO, 389 "source", CTLFLAG_RW | CTLTYPE_STRING, 390 &fclk_configs[i], i, 391 zy7_devcfg_fclk_sysctl_source, 392 "A", "Clock source"); 393 } 394 395 return (0); 396} 397 398/* Enable programming the PL through PCAP. */ 399static void 400zy7_devcfg_init_hw(struct zy7_devcfg_softc *sc) 401{ 402 403 DEVCFG_SC_ASSERT_LOCKED(sc); 404 405 /* Set devcfg control register. */ 406 WR4(sc, ZY7_DEVCFG_CTRL, 407 ZY7_DEVCFG_CTRL_PCFG_PROG_B | 408 ZY7_DEVCFG_CTRL_PCAP_PR | 409 ZY7_DEVCFG_CTRL_PCAP_MODE | 410 ZY7_DEVCFG_CTRL_USER_MODE | 411 ZY7_DEVCFG_CTRL_RESVD_WR11 | 412 ZY7_DEVCFG_CTRL_SPNIDEN | 413 ZY7_DEVCFG_CTRL_SPIDEN | 414 ZY7_DEVCFG_CTRL_NIDEN | 415 ZY7_DEVCFG_CTRL_DBGEN | 416 ZY7_DEVCFG_CTRL_DAP_EN_MASK); 417 418 /* Turn off internal PCAP loopback. */ 419 WR4(sc, ZY7_DEVCFG_MCTRL, RD4(sc, ZY7_DEVCFG_MCTRL) & 420 ~ZY7_DEVCFG_MCTRL_INT_PCAP_LPBK); 421} 422 423/* Clear previous configuration of the PL by asserting PROG_B. */ 424static int 425zy7_devcfg_reset_pl(struct zy7_devcfg_softc *sc) 426{ 427 uint32_t devcfg_ctl; 428 int tries, err; 429 430 DEVCFG_SC_ASSERT_LOCKED(sc); 431 432 devcfg_ctl = RD4(sc, ZY7_DEVCFG_CTRL); 433 434 /* Clear sticky bits and set up INIT signal positive edge interrupt. */ 435 WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL); 436 WR4(sc, ZY7_DEVCFG_INT_MASK, ~ZY7_DEVCFG_INT_PCFG_INIT_PE); 437 438 /* Deassert PROG_B (active low). */ 439 devcfg_ctl |= ZY7_DEVCFG_CTRL_PCFG_PROG_B; 440 WR4(sc, ZY7_DEVCFG_CTRL, devcfg_ctl); 441 442 /* 443 * Wait for INIT to assert. If it is already asserted, we may not get 444 * an edge interrupt so cancel it and continue. 445 */ 446 if ((RD4(sc, ZY7_DEVCFG_STATUS) & 447 ZY7_DEVCFG_STATUS_PCFG_INIT) != 0) { 448 /* Already asserted. Cancel interrupt. */ 449 WR4(sc, ZY7_DEVCFG_INT_MASK, ~0); 450 } 451 else { 452 /* Wait for positive edge interrupt. */ 453 err = mtx_sleep(sc, &sc->sc_mtx, PCATCH, "zy7i1", hz); 454 if (err != 0) 455 return (err); 456 } 457 458 /* Reassert PROG_B (active low). */ 459 devcfg_ctl &= ~ZY7_DEVCFG_CTRL_PCFG_PROG_B; 460 WR4(sc, ZY7_DEVCFG_CTRL, devcfg_ctl); 461 462 /* Wait for INIT deasserted. This happens almost instantly. */ 463 tries = 0; 464 while ((RD4(sc, ZY7_DEVCFG_STATUS) & 465 ZY7_DEVCFG_STATUS_PCFG_INIT) != 0) { 466 if (++tries >= 100) 467 return (EIO); 468 DELAY(5); 469 } 470 471 /* Clear sticky bits and set up INIT positive edge interrupt. */ 472 WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL); 473 WR4(sc, ZY7_DEVCFG_INT_MASK, ~ZY7_DEVCFG_INT_PCFG_INIT_PE); 474 475 /* Deassert PROG_B again. */ 476 devcfg_ctl |= ZY7_DEVCFG_CTRL_PCFG_PROG_B; 477 WR4(sc, ZY7_DEVCFG_CTRL, devcfg_ctl); 478 479 /* 480 * Wait for INIT asserted indicating FPGA internal initialization 481 * is complete. 482 */ 483 err = mtx_sleep(sc, &sc->sc_mtx, PCATCH, "zy7i2", hz); 484 if (err != 0) 485 return (err); 486 487 /* Clear sticky DONE bit in interrupt status. */ 488 WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL); 489 490 return (0); 491} 492 493/* Callback function for bus_dmamap_load(). */ 494static void 495zy7_dma_cb2(void *arg, bus_dma_segment_t *seg, int nsegs, int error) 496{ 497 if (!error && nsegs == 1) 498 *(bus_addr_t *)arg = seg[0].ds_addr; 499} 500 501static int 502zy7_devcfg_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 503{ 504 struct zy7_devcfg_softc *sc = dev->si_drv1; 505 int err; 506 507 DEVCFG_SC_LOCK(sc); 508 if (sc->is_open) { 509 DEVCFG_SC_UNLOCK(sc); 510 return (EBUSY); 511 } 512 513 sc->dma_map = NULL; 514 err = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 4, 0, 515 BUS_SPACE_MAXADDR_32BIT, 516 BUS_SPACE_MAXADDR, 517 NULL, NULL, 518 PAGE_SIZE, 519 1, 520 PAGE_SIZE, 521 0, 522 busdma_lock_mutex, 523 &sc->sc_mtx, 524 &sc->dma_tag); 525 if (err) { 526 DEVCFG_SC_UNLOCK(sc); 527 return (err); 528 } 529 530 sc->is_open = 1; 531 DEVCFG_SC_UNLOCK(sc); 532 return (0); 533} 534 535static int 536zy7_devcfg_write(struct cdev *dev, struct uio *uio, int ioflag) 537{ 538 struct zy7_devcfg_softc *sc = dev->si_drv1; 539 void *dma_mem; 540 bus_addr_t dma_physaddr; 541 int segsz, err; 542 543 DEVCFG_SC_LOCK(sc); 544 545 /* First write? Reset PL. */ 546 if (uio->uio_offset == 0 && uio->uio_resid > 0) { 547 zy7_devcfg_init_hw(sc); 548 zy7_slcr_preload_pl(); 549 err = zy7_devcfg_reset_pl(sc); 550 if (err != 0) { 551 DEVCFG_SC_UNLOCK(sc); 552 return (err); 553 } 554 } 555 556 /* Allocate dma memory and load. */ 557 err = bus_dmamem_alloc(sc->dma_tag, &dma_mem, BUS_DMA_NOWAIT, 558 &sc->dma_map); 559 if (err != 0) { 560 DEVCFG_SC_UNLOCK(sc); 561 return (err); 562 } 563 err = bus_dmamap_load(sc->dma_tag, sc->dma_map, dma_mem, PAGE_SIZE, 564 zy7_dma_cb2, &dma_physaddr, 0); 565 if (err != 0) { 566 bus_dmamem_free(sc->dma_tag, dma_mem, sc->dma_map); 567 DEVCFG_SC_UNLOCK(sc); 568 return (err); 569 } 570 571 while (uio->uio_resid > 0) { 572 /* If DONE signal has been set, we shouldn't write anymore. */ 573 if ((RD4(sc, ZY7_DEVCFG_INT_STATUS) & 574 ZY7_DEVCFG_INT_PCFG_DONE) != 0) { 575 err = EIO; 576 break; 577 } 578 579 /* uiomove the data from user buffer to our dma map. */ 580 segsz = MIN(PAGE_SIZE, uio->uio_resid); 581 DEVCFG_SC_UNLOCK(sc); 582 err = uiomove(dma_mem, segsz, uio); 583 DEVCFG_SC_LOCK(sc); 584 if (err != 0) 585 break; 586 587 /* Flush the cache to memory. */ 588 bus_dmamap_sync(sc->dma_tag, sc->dma_map, 589 BUS_DMASYNC_PREWRITE); 590 591 /* Program devcfg's DMA engine. The ordering of these 592 * register writes is critical. 593 */ 594 if (uio->uio_resid > segsz) 595 WR4(sc, ZY7_DEVCFG_DMA_SRC_ADDR, 596 (uint32_t) dma_physaddr); 597 else 598 WR4(sc, ZY7_DEVCFG_DMA_SRC_ADDR, 599 (uint32_t) dma_physaddr | 600 ZY7_DEVCFG_DMA_ADDR_WAIT_PCAP); 601 WR4(sc, ZY7_DEVCFG_DMA_DST_ADDR, ZY7_DEVCFG_DMA_ADDR_ILLEGAL); 602 WR4(sc, ZY7_DEVCFG_DMA_SRC_LEN, (segsz+3)/4); 603 WR4(sc, ZY7_DEVCFG_DMA_DST_LEN, 0); 604 605 /* Now clear done bit and set up DMA done interrupt. */ 606 WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL); 607 WR4(sc, ZY7_DEVCFG_INT_MASK, ~ZY7_DEVCFG_INT_DMA_DONE); 608 609 /* Wait for DMA done interrupt. */ 610 err = mtx_sleep(sc->dma_map, &sc->sc_mtx, PCATCH, 611 "zy7dma", hz); 612 if (err != 0) 613 break; 614 615 bus_dmamap_sync(sc->dma_tag, sc->dma_map, 616 BUS_DMASYNC_POSTWRITE); 617 618 /* Check DONE signal. */ 619 if ((RD4(sc, ZY7_DEVCFG_INT_STATUS) & 620 ZY7_DEVCFG_INT_PCFG_DONE) != 0) 621 zy7_slcr_postload_pl(zy7_en_level_shifters); 622 } 623 624 bus_dmamap_unload(sc->dma_tag, sc->dma_map); 625 bus_dmamem_free(sc->dma_tag, dma_mem, sc->dma_map); 626 DEVCFG_SC_UNLOCK(sc); 627 return (err); 628} 629 630static int 631zy7_devcfg_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 632{ 633 struct zy7_devcfg_softc *sc = dev->si_drv1; 634 635 DEVCFG_SC_LOCK(sc); 636 sc->is_open = 0; 637 bus_dma_tag_destroy(sc->dma_tag); 638 DEVCFG_SC_UNLOCK(sc); 639 640 zy7_slcr_postload_pl(zy7_en_level_shifters); 641 642 return (0); 643} 644 645static void 646zy7_devcfg_intr(void *arg) 647{ 648 struct zy7_devcfg_softc *sc = (struct zy7_devcfg_softc *)arg; 649 uint32_t istatus, imask; 650 651 DEVCFG_SC_LOCK(sc); 652 653 istatus = RD4(sc, ZY7_DEVCFG_INT_STATUS); 654 imask = ~RD4(sc, ZY7_DEVCFG_INT_MASK); 655 656 /* Turn interrupt off. */ 657 WR4(sc, ZY7_DEVCFG_INT_MASK, ~0); 658 659 if ((istatus & imask) == 0) { 660 DEVCFG_SC_UNLOCK(sc); 661 return; 662 } 663 664 /* DMA done? */ 665 if ((istatus & ZY7_DEVCFG_INT_DMA_DONE) != 0) 666 wakeup(sc->dma_map); 667 668 /* INIT_B positive edge? */ 669 if ((istatus & ZY7_DEVCFG_INT_PCFG_INIT_PE) != 0) 670 wakeup(sc); 671 672 DEVCFG_SC_UNLOCK(sc); 673} 674 675/* zy7_devcfg_sysctl_pl_done() returns status of the PL_DONE signal. 676 */ 677static int 678zy7_devcfg_sysctl_pl_done(SYSCTL_HANDLER_ARGS) 679{ 680 struct zy7_devcfg_softc *sc = zy7_devcfg_softc_p; 681 int pl_done = 0; 682 683 if (sc) { 684 DEVCFG_SC_LOCK(sc); 685 686 /* PCFG_DONE bit is sticky. Clear it before checking it. */ 687 WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_PCFG_DONE); 688 pl_done = ((RD4(sc, ZY7_DEVCFG_INT_STATUS) & 689 ZY7_DEVCFG_INT_PCFG_DONE) != 0); 690 691 DEVCFG_SC_UNLOCK(sc); 692 } 693 return (sysctl_handle_int(oidp, &pl_done, 0, req)); 694} 695 696static int 697zy7_devcfg_probe(device_t dev) 698{ 699 700 if (!ofw_bus_status_okay(dev)) 701 return (ENXIO); 702 703 if (!ofw_bus_is_compatible(dev, "xlnx,zy7_devcfg")) 704 return (ENXIO); 705 706 device_set_desc(dev, "Zynq devcfg block"); 707 return (0); 708} 709 710static int zy7_devcfg_detach(device_t dev); 711 712static int 713zy7_devcfg_attach(device_t dev) 714{ 715 struct zy7_devcfg_softc *sc = device_get_softc(dev); 716 int i; 717 int rid, err; 718 719 /* Allow only one attach. */ 720 if (zy7_devcfg_softc_p != NULL) 721 return (ENXIO); 722 723 sc->dev = dev; 724 725 DEVCFG_SC_LOCK_INIT(sc); 726 727 /* Get memory resource. */ 728 rid = 0; 729 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 730 RF_ACTIVE); 731 if (sc->mem_res == NULL) { 732 device_printf(dev, "could not allocate memory resources.\n"); 733 zy7_devcfg_detach(dev); 734 return (ENOMEM); 735 } 736 737 /* Allocate IRQ. */ 738 rid = 0; 739 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 740 RF_ACTIVE); 741 if (sc->irq_res == NULL) { 742 device_printf(dev, "cannot allocate IRQ\n"); 743 zy7_devcfg_detach(dev); 744 return (ENOMEM); 745 } 746 747 /* Activate the interrupt. */ 748 err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 749 NULL, zy7_devcfg_intr, sc, &sc->intrhandle); 750 if (err) { 751 device_printf(dev, "cannot setup IRQ\n"); 752 zy7_devcfg_detach(dev); 753 return (err); 754 } 755 756 /* Create /dev/devcfg */ 757 sc->sc_ctl_dev = make_dev(&zy7_devcfg_cdevsw, 0, 758 UID_ROOT, GID_WHEEL, 0600, "devcfg"); 759 if (sc->sc_ctl_dev == NULL) { 760 device_printf(dev, "failed to create /dev/devcfg"); 761 zy7_devcfg_detach(dev); 762 return (ENXIO); 763 } 764 sc->sc_ctl_dev->si_drv1 = sc; 765 766 zy7_devcfg_softc_p = sc; 767 768 /* Unlock devcfg registers. */ 769 WR4(sc, ZY7_DEVCFG_UNLOCK, ZY7_DEVCFG_UNLOCK_MAGIC); 770 771 /* Make sure interrupts are completely disabled. */ 772 WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL); 773 WR4(sc, ZY7_DEVCFG_INT_MASK, 0xffffffff); 774 775 /* Get PS_VERS for SYSCTL. */ 776 zy7_ps_vers = (RD4(sc, ZY7_DEVCFG_MCTRL) & 777 ZY7_DEVCFG_MCTRL_PS_VERS_MASK) >> 778 ZY7_DEVCFG_MCTRL_PS_VERS_SHIFT; 779 780 for (i = 0; i < FCLK_NUM; i++) { 781 fclk_configs[i].source = zy7_pl_fclk_get_source(i); 782 fclk_configs[i].actual_frequency = 783 zy7_pl_fclk_enabled(i) ? zy7_pl_fclk_get_freq(i) : 0; 784 /* Initially assume actual frequency is the configure one */ 785 fclk_configs[i].frequency = fclk_configs[i].actual_frequency; 786 } 787 788 if (zy7_devcfg_init_fclk_sysctl(sc) < 0) 789 device_printf(dev, "failed to initialized sysctl tree\n"); 790 791 return (0); 792} 793 794static int 795zy7_devcfg_detach(device_t dev) 796{ 797 struct zy7_devcfg_softc *sc = device_get_softc(dev); 798 799 if (sc->sysctl_tree_top != NULL) { 800 sysctl_ctx_free(&sc->sysctl_tree); 801 sc->sysctl_tree_top = NULL; 802 } 803 804 if (device_is_attached(dev)) 805 bus_generic_detach(dev); 806 807 /* Get rid of /dev/devcfg0. */ 808 if (sc->sc_ctl_dev != NULL) 809 destroy_dev(sc->sc_ctl_dev); 810 811 /* Teardown and release interrupt. */ 812 if (sc->irq_res != NULL) { 813 if (sc->intrhandle) 814 bus_teardown_intr(dev, sc->irq_res, sc->intrhandle); 815 bus_release_resource(dev, SYS_RES_IRQ, 816 rman_get_rid(sc->irq_res), sc->irq_res); 817 } 818 819 /* Release memory resource. */ 820 if (sc->mem_res != NULL) 821 bus_release_resource(dev, SYS_RES_MEMORY, 822 rman_get_rid(sc->mem_res), sc->mem_res); 823 824 zy7_devcfg_softc_p = NULL; 825 826 DEVCFG_SC_LOCK_DESTROY(sc); 827 828 return (0); 829} 830 831static device_method_t zy7_devcfg_methods[] = { 832 /* device_if */ 833 DEVMETHOD(device_probe, zy7_devcfg_probe), 834 DEVMETHOD(device_attach, zy7_devcfg_attach), 835 DEVMETHOD(device_detach, zy7_devcfg_detach), 836 837 DEVMETHOD_END 838}; 839 840static driver_t zy7_devcfg_driver = { 841 "zy7_devcfg", 842 zy7_devcfg_methods, 843 sizeof(struct zy7_devcfg_softc), 844}; 845static devclass_t zy7_devcfg_devclass; 846 847DRIVER_MODULE(zy7_devcfg, simplebus, zy7_devcfg_driver, zy7_devcfg_devclass, \ 848 0, 0); 849MODULE_DEPEND(zy7_devcfg, zy7_slcr, 1, 1, 1); 850