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