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