1 1.1 rkujawa /* $NetBSD: bestcomm.c,v 1.1 2026/06/27 13:28:34 rkujawa Exp $ */ 2 1.1 rkujawa 3 1.1 rkujawa /*- 4 1.1 rkujawa * Copyright (c) 2009, 2026 The NetBSD Foundation, Inc. 5 1.1 rkujawa * All rights reserved. 6 1.1 rkujawa * 7 1.1 rkujawa * This code is derived from software contributed to The NetBSD Foundation 8 1.1 rkujawa * by Radoslaw Kujawa and Robert Swindells. 9 1.1 rkujawa * 10 1.1 rkujawa * Redistribution and use in source and binary forms, with or without 11 1.1 rkujawa * modification, are permitted provided that the following conditions 12 1.1 rkujawa * are met: 13 1.1 rkujawa * 1. Redistributions of source code must retain the above copyright 14 1.1 rkujawa * notice, this list of conditions and the following disclaimer. 15 1.1 rkujawa * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 rkujawa * notice, this list of conditions and the following disclaimer in the 17 1.1 rkujawa * documentation and/or other materials provided with the distribution. 18 1.1 rkujawa * 19 1.1 rkujawa * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 rkujawa * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 rkujawa * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 rkujawa * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 rkujawa * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 rkujawa * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 rkujawa * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 rkujawa * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 rkujawa * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 rkujawa * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 rkujawa * POSSIBILITY OF SUCH DAMAGE. 30 1.1 rkujawa */ 31 1.1 rkujawa 32 1.1 rkujawa /* 33 1.1 rkujawa * Driver for the MPC5200B BestComm SDMA engine. 34 1.1 rkujawa * 35 1.1 rkujawa * BestComm is a microcoded processor that runs DMA tasks from on-chip SRAM. 36 1.1 rkujawa */ 37 1.1 rkujawa 38 1.1 rkujawa #include <sys/cdefs.h> 39 1.1 rkujawa __KERNEL_RCSID(0, "$NetBSD: bestcomm.c,v 1.1 2026/06/27 13:28:34 rkujawa Exp $"); 40 1.1 rkujawa 41 1.1 rkujawa #include <sys/param.h> 42 1.1 rkujawa #include <sys/systm.h> 43 1.1 rkujawa #include <sys/device.h> 44 1.1 rkujawa #include <sys/bus.h> 45 1.1 rkujawa 46 1.1 rkujawa #include <dev/ofw/openfirm.h> 47 1.1 rkujawa 48 1.1 rkujawa #include <machine/autoconf.h> 49 1.1 rkujawa 50 1.1 rkujawa #include <powerpc/pic/picvar.h> 51 1.1 rkujawa 52 1.1 rkujawa #include <powerpc/mpc5200/obiovar.h> 53 1.1 rkujawa #include <powerpc/mpc5200/mpc5200reg.h> 54 1.1 rkujawa #include <powerpc/mpc5200/bestcommreg.h> 55 1.1 rkujawa #include <powerpc/mpc5200/sramvar.h> 56 1.1 rkujawa #include <powerpc/mpc5200/bestcommvar.h> 57 1.1 rkujawa #include <powerpc/mpc5200/bestcomm_image.h> 58 1.1 rkujawa 59 1.1 rkujawa /* 60 1.1 rkujawa * The task table MUST be aligned so that the function-descriptor relocation 61 1.1 rkujawa * (which replaces a descriptor's high 24 bits with the TaskBar's) is exact. 62 1.1 rkujawa */ 63 1.1 rkujawa #define BESTCOMM_TASKBAR_ALIGN 0x100 64 1.1 rkujawa 65 1.1 rkujawa #define BESTCOMM_CASCADE_IRQ 64 66 1.1 rkujawa 67 1.1 rkujawa static int bestcomm_match(device_t, cfdata_t, void *); 68 1.1 rkujawa static void bestcomm_attach(device_t, device_t, void *); 69 1.1 rkujawa static void bestcomm_load_image(device_t); 70 1.1 rkujawa 71 1.1 rkujawa CFATTACH_DECL_NEW(bestcomm, sizeof(struct bestcomm_softc), 72 1.1 rkujawa bestcomm_match, bestcomm_attach, NULL, NULL); 73 1.1 rkujawa 74 1.1 rkujawa static void bestcomm_enable_irq(struct pic_ops *, int, int); 75 1.1 rkujawa static void bestcomm_disable_irq(struct pic_ops *, int); 76 1.1 rkujawa static int bestcomm_get_irq(struct pic_ops *, int); 77 1.1 rkujawa static void bestcomm_ack_irq(struct pic_ops *, int); 78 1.1 rkujawa static void bestcomm_establish_irq(struct pic_ops *, int, int, int); 79 1.1 rkujawa 80 1.1 rkujawa static struct bestcomm_softc *bestcomm_sc; 81 1.1 rkujawa 82 1.1 rkujawa static inline uint32_t 83 1.1 rkujawa sdma_read(struct bestcomm_ops *b, bus_size_t off) 84 1.1 rkujawa { 85 1.1 rkujawa return bus_space_read_4(b->bst, b->bsh, off); 86 1.1 rkujawa } 87 1.1 rkujawa 88 1.1 rkujawa static inline void 89 1.1 rkujawa sdma_write(struct bestcomm_ops *b, bus_size_t off, uint32_t val) 90 1.1 rkujawa { 91 1.1 rkujawa bus_space_write_4(b->bst, b->bsh, off, val); 92 1.1 rkujawa } 93 1.1 rkujawa 94 1.1 rkujawa static int 95 1.1 rkujawa bestcomm_match(device_t parent, cfdata_t cf, void *aux) 96 1.1 rkujawa { 97 1.1 rkujawa struct obio_attach_args *oba = aux; 98 1.1 rkujawa char compat[40]; 99 1.1 rkujawa int len; 100 1.1 rkujawa 101 1.1 rkujawa if (strcmp(oba->obio_name, "bestcomm") == 0 || 102 1.1 rkujawa strcmp(oba->obio_name, "sdma") == 0) 103 1.1 rkujawa return 1; 104 1.1 rkujawa 105 1.1 rkujawa len = OF_getprop(oba->obio_node, "compatible", compat, sizeof(compat)); 106 1.1 rkujawa if (len > 0 && 107 1.1 rkujawa (strcmp(compat, "mpc5200-bestcomm") == 0 || 108 1.1 rkujawa strcmp(compat, "mpc5200b-bestcomm") == 0)) 109 1.1 rkujawa return 1; 110 1.1 rkujawa 111 1.1 rkujawa return 0; 112 1.1 rkujawa } 113 1.1 rkujawa 114 1.1 rkujawa static void 115 1.1 rkujawa bestcomm_attach(device_t parent, device_t self, void *aux) 116 1.1 rkujawa { 117 1.1 rkujawa struct bestcomm_softc *sc = device_private(self); 118 1.1 rkujawa struct obio_attach_args *oba = aux; 119 1.1 rkujawa struct bestcomm_ops *b = &sc->sc_pic; 120 1.1 rkujawa struct pic_ops *pic = &b->pic; 121 1.1 rkujawa bus_size_t size; 122 1.1 rkujawa int i; 123 1.1 rkujawa 124 1.1 rkujawa sc->sc_dev = self; 125 1.1 rkujawa sc->sc_dmat = oba->obio_dmat; 126 1.1 rkujawa b->bst = oba->obio_bst; 127 1.1 rkujawa 128 1.1 rkujawa size = oba->obio_size != 0 ? oba->obio_size : SDMA_REG_SIZE; 129 1.1 rkujawa if (bus_space_map(b->bst, oba->obio_addr, size, 0, &b->bsh) != 0) { 130 1.1 rkujawa aprint_error(": can't map registers\n"); 131 1.1 rkujawa return; 132 1.1 rkujawa } 133 1.1 rkujawa 134 1.1 rkujawa /* 135 1.1 rkujawa * Bring the engine to an idle state 136 1.1 rkujawa */ 137 1.1 rkujawa for (i = 0; i < SDMA_NTASKS / 2; i++) 138 1.1 rkujawa sdma_write(b, SDMA_TCR + i * sizeof(uint32_t), 0); 139 1.1 rkujawa 140 1.1 rkujawa b->int_mask = 0xffffffff; 141 1.1 rkujawa sdma_write(b, SDMA_INT_MASK, b->int_mask); 142 1.1 rkujawa sdma_write(b, SDMA_INT_PEND, SDMA_INT_IMPL); 143 1.1 rkujawa 144 1.1 rkujawa pic->pic_cookie = b; 145 1.1 rkujawa pic->pic_numintrs = SDMA_NTASKS; 146 1.1 rkujawa pic->pic_enable_irq = bestcomm_enable_irq; 147 1.1 rkujawa pic->pic_reenable_irq = bestcomm_enable_irq; 148 1.1 rkujawa pic->pic_disable_irq = bestcomm_disable_irq; 149 1.1 rkujawa pic->pic_get_irq = bestcomm_get_irq; 150 1.1 rkujawa pic->pic_ack_irq = bestcomm_ack_irq; 151 1.1 rkujawa pic->pic_establish_irq = bestcomm_establish_irq; 152 1.1 rkujawa pic->pic_finish_setup = NULL; 153 1.1 rkujawa strlcpy(pic->pic_name, device_xname(self), sizeof(pic->pic_name)); 154 1.1 rkujawa 155 1.1 rkujawa pic_add(pic); 156 1.1 rkujawa 157 1.1 rkujawa /* 158 1.1 rkujawa * Cascade the secondary controller onto the SIU 159 1.1 rkujawa */ 160 1.1 rkujawa sc->sc_cascade = intr_establish(BESTCOMM_CASCADE_IRQ, IST_LEVEL, 161 1.1 rkujawa IPL_NET, pic_handle_intr, pic); 162 1.1 rkujawa 163 1.1 rkujawa bestcomm_sc = sc; 164 1.1 rkujawa 165 1.1 rkujawa aprint_normal(": BestComm SDMA, %d tasks, %d interrupt sources\n", 166 1.1 rkujawa SDMA_NTASKS, SDMA_NTASKS); 167 1.1 rkujawa 168 1.1 rkujawa config_interrupts(self, bestcomm_load_image); 169 1.1 rkujawa } 170 1.1 rkujawa 171 1.1 rkujawa bool 172 1.1 rkujawa bestcomm_available(void) 173 1.1 rkujawa { 174 1.1 rkujawa return bestcomm_sc != NULL; 175 1.1 rkujawa } 176 1.1 rkujawa 177 1.1 rkujawa /* 178 1.1 rkujawa * Set the low 16 bits (the signed increment) of an increment word while 179 1.1 rkujawa * preserving the high half, matching the task layout. 180 1.1 rkujawa */ 181 1.1 rkujawa static void 182 1.1 rkujawa bestcomm_set_incr(volatile uint32_t *incw, int value) 183 1.1 rkujawa { 184 1.1 rkujawa *incw = (*incw & 0xffff0000) | ((uint16_t)value); 185 1.1 rkujawa } 186 1.1 rkujawa 187 1.1 rkujawa /* 188 1.1 rkujawa * Set up a single-pointer FIFO-to-memory BD task (the FEC receive shape). 189 1.1 rkujawa */ 190 1.1 rkujawa int 191 1.1 rkujawa bestcomm_bd_setup(struct bestcomm_bdring *br, int task, 192 1.1 rkujawa const struct bestcomm_bd_layout *l, bus_addr_t fifo_pa, u_int nbd, 193 1.1 rkujawa uint32_t maxbuf, int datasize, int initiator, int prio) 194 1.1 rkujawa { 195 1.1 rkujawa struct bestcomm_softc *sc = bestcomm_sc; 196 1.1 rkujawa struct bestcomm_ops *b; 197 1.1 rkujawa struct bestcomm_tdt *tdt; 198 1.1 rkujawa volatile uint32_t *var, *inc; 199 1.1 rkujawa bus_addr_t ring_pa, tcr_pa; 200 1.1 rkujawa uint8_t szbyte; 201 1.1 rkujawa 202 1.1 rkujawa if (sc == NULL || sc->sc_image_kva == NULL) 203 1.1 rkujawa return ENXIO; 204 1.1 rkujawa b = &sc->sc_pic; 205 1.1 rkujawa 206 1.1 rkujawa ring_pa = sram_alloc(nbd * sizeof(uint32_t) * 2, sizeof(uint32_t) * 2); 207 1.1 rkujawa if (ring_pa == 0) 208 1.1 rkujawa return ENOMEM; 209 1.1 rkujawa 210 1.1 rkujawa br->br_task = task; 211 1.1 rkujawa br->br_bd_pa = ring_pa; 212 1.1 rkujawa br->br_bd = sram_kva(ring_pa); 213 1.1 rkujawa br->br_nbd = nbd; 214 1.1 rkujawa br->br_bdflag = l->bdflag; 215 1.1 rkujawa memset(br->br_bd, 0, nbd * sizeof(uint32_t) * 2); 216 1.1 rkujawa 217 1.1 rkujawa tdt = (struct bestcomm_tdt *)((char *)sc->sc_image_kva + 218 1.1 rkujawa task * sizeof(struct bestcomm_tdt)); 219 1.1 rkujawa var = (volatile uint32_t *)sram_kva(tdt->tdt_var); 220 1.1 rkujawa inc = var + 24; 221 1.1 rkujawa 222 1.1 rkujawa tcr_pa = MPC5200_MBAR_DEFAULT + MPC5200_REG_SDMA + SDMA_TCR + task * 2; 223 1.1 rkujawa 224 1.1 rkujawa var[l->fifo_var] = fifo_pa; /* peripheral FIFO */ 225 1.1 rkujawa var[l->enable_var] = tcr_pa; /* task's own TCR */ 226 1.1 rkujawa var[l->base_var] = ring_pa; /* BD ring base */ 227 1.1 rkujawa var[l->base_var + 1] = ring_pa + (nbd - 1) * 8; /* last */ 228 1.1 rkujawa var[l->base_var + 2] = ring_pa; /* current/start */ 229 1.1 rkujawa var[l->bytes_var] = maxbuf; /* per-buffer cap */ 230 1.1 rkujawa if (l->drd_var >= 0) /* flag-carrying DRD */ 231 1.1 rkujawa var[l->drd_var] = tdt->tdt_start + l->drd_off; 232 1.1 rkujawa bestcomm_set_incr(&inc[0], -datasize); /* IncrBytes */ 233 1.1 rkujawa bestcomm_set_incr(&inc[1], datasize); /* memory-side incr */ 234 1.1 rkujawa bestcomm_set_incr(&inc[2], 1); /* misalign adjust */ 235 1.1 rkujawa 236 1.1 rkujawa ((volatile uint8_t *)&tdt->tdt_fdt)[3] = 0x07; /* task pragma */ 237 1.1 rkujawa 238 1.1 rkujawa /* datasize transfer size on both sides (even/odd nibble). */ 239 1.1 rkujawa szbyte = bus_space_read_1(b->bst, b->bsh, SDMA_SIZE_BYTE(task)); 240 1.1 rkujawa if (task & 1) 241 1.1 rkujawa szbyte = (szbyte & 0xf0) | SDMA_SIZE_FIELD(datasize, datasize); 242 1.1 rkujawa else 243 1.1 rkujawa szbyte = (szbyte & 0x0f) | 244 1.1 rkujawa (SDMA_SIZE_FIELD(datasize, datasize) << 4); 245 1.1 rkujawa bus_space_write_1(b->bst, b->bsh, SDMA_SIZE_BYTE(task), szbyte); 246 1.1 rkujawa 247 1.1 rkujawa /* Auto-restart the task after each buffer; leave it disabled for now. */ 248 1.1 rkujawa bus_space_write_2(b->bst, b->bsh, SDMA_TCR_TASK(task), 249 1.1 rkujawa SDMA_TCR_AUTOSTART | (task & SDMA_TCR_AUTOTASK_MASK)); 250 1.1 rkujawa 251 1.1 rkujawa /* Give the (image-baked) hardware initiator a scheduling priority. */ 252 1.1 rkujawa bus_space_write_1(b->bst, b->bsh, SDMA_IPR_INIT(initiator), prio & 0x07); 253 1.1 rkujawa 254 1.1 rkujawa __asm volatile ("sync" ::: "memory"); 255 1.1 rkujawa return 0; 256 1.1 rkujawa } 257 1.1 rkujawa 258 1.1 rkujawa /* 259 1.1 rkujawa * Release a BD task's resources 260 1.1 rkujawa */ 261 1.1 rkujawa void 262 1.1 rkujawa bestcomm_bd_teardown(struct bestcomm_bdring *br) 263 1.1 rkujawa { 264 1.1 rkujawa if (br->br_bd_pa == 0) 265 1.1 rkujawa return; 266 1.1 rkujawa 267 1.1 rkujawa bestcomm_task_stop(br->br_task); 268 1.1 rkujawa sram_free(br->br_bd_pa, br->br_nbd * sizeof(uint32_t) * 2); 269 1.1 rkujawa br->br_bd = NULL; 270 1.1 rkujawa br->br_bd_pa = 0; 271 1.1 rkujawa br->br_nbd = 0; 272 1.1 rkujawa } 273 1.1 rkujawa 274 1.1 rkujawa void 275 1.1 rkujawa bestcomm_bd_post(struct bestcomm_bdring *br, u_int idx, bus_addr_t buf_pa, 276 1.1 rkujawa uint32_t size, uint32_t flags) 277 1.1 rkujawa { 278 1.1 rkujawa volatile uint32_t *bd = (volatile uint32_t *)br->br_bd + idx * 2; 279 1.1 rkujawa uint32_t status; 280 1.1 rkujawa 281 1.1 rkujawa if (br->br_bdflag) 282 1.1 rkujawa status = (flags & 0x0c000000) | (size & 0x03ffffff); 283 1.1 rkujawa else 284 1.1 rkujawa status = size & 0x7fffffff; 285 1.1 rkujawa 286 1.1 rkujawa bd[1] = buf_pa; /* data pointer */ 287 1.1 rkujawa __asm volatile ("sync" ::: "memory"); 288 1.1 rkujawa bd[0] = status | BESTCOMM_BD_READY; /* arm for the engine */ 289 1.1 rkujawa __asm volatile ("sync" ::: "memory"); 290 1.1 rkujawa } 291 1.1 rkujawa 292 1.1 rkujawa uint32_t 293 1.1 rkujawa bestcomm_bd_status(struct bestcomm_bdring *br, u_int idx) 294 1.1 rkujawa { 295 1.1 rkujawa volatile uint32_t *bd = (volatile uint32_t *)br->br_bd + idx * 2; 296 1.1 rkujawa 297 1.1 rkujawa return bd[0]; 298 1.1 rkujawa } 299 1.1 rkujawa 300 1.1 rkujawa /* 301 1.1 rkujawa * Stamp a runtime initiator into a task 302 1.1 rkujawa */ 303 1.1 rkujawa void 304 1.1 rkujawa bestcomm_task_set_initiator(int task, int initiator, const uint16_t *drd_offs, 305 1.1 rkujawa u_int ndrd) 306 1.1 rkujawa { 307 1.1 rkujawa struct bestcomm_softc *sc = bestcomm_sc; 308 1.1 rkujawa struct bestcomm_ops *b; 309 1.1 rkujawa struct bestcomm_tdt *tdt; 310 1.1 rkujawa uint16_t tcr; 311 1.1 rkujawa u_int i; 312 1.1 rkujawa bool ext = false; 313 1.1 rkujawa 314 1.1 rkujawa if (sc == NULL || sc->sc_image_kva == NULL) 315 1.1 rkujawa return; 316 1.1 rkujawa b = &sc->sc_pic; 317 1.1 rkujawa tdt = (struct bestcomm_tdt *)((char *)sc->sc_image_kva + 318 1.1 rkujawa task * sizeof(struct bestcomm_tdt)); 319 1.1 rkujawa 320 1.1 rkujawa /* Task own-initiator field in the TCR (preserve the other bits). */ 321 1.1 rkujawa tcr = bus_space_read_2(b->bst, b->bsh, SDMA_TCR_TASK(task)); 322 1.1 rkujawa tcr = (tcr & ~SDMA_TCR_INIT_MASK) | 323 1.1 rkujawa (((uint16_t)initiator << SDMA_TCR_INIT_SHIFT) & SDMA_TCR_INIT_MASK); 324 1.1 rkujawa bus_space_write_2(b->bst, b->bsh, SDMA_TCR_TASK(task), tcr); 325 1.1 rkujawa 326 1.1 rkujawa for (i = 0; i < ndrd; i++) { 327 1.1 rkujawa volatile uint32_t *drd = 328 1.1 rkujawa (volatile uint32_t *)sram_kva(tdt->tdt_start + drd_offs[i]); 329 1.1 rkujawa 330 1.1 rkujawa if (!ext) { 331 1.1 rkujawa if (((*drd & SDMA_DRD_INIT_MASK) >> SDMA_DRD_INIT_SHIFT) != 332 1.1 rkujawa SDMA_INITIATOR_ALWAYS) 333 1.1 rkujawa *drd = (*drd & ~SDMA_DRD_INIT_MASK) | 334 1.1 rkujawa ((uint32_t)initiator << SDMA_DRD_INIT_SHIFT); 335 1.1 rkujawa ext = (*drd & SDMA_DRD_EXT) != 0; 336 1.1 rkujawa } else { 337 1.1 rkujawa /* This word is a DRD extension operand; skip, then 338 1.1 rkujawa * resume looking for descriptors once it ends. */ 339 1.1 rkujawa ext = (*drd & SDMA_DRD_EXT) != 0; 340 1.1 rkujawa } 341 1.1 rkujawa } 342 1.1 rkujawa 343 1.1 rkujawa __asm volatile ("sync" ::: "memory"); 344 1.1 rkujawa } 345 1.1 rkujawa 346 1.1 rkujawa void 347 1.1 rkujawa bestcomm_task_start(int task) 348 1.1 rkujawa { 349 1.1 rkujawa struct bestcomm_ops *b = &bestcomm_sc->sc_pic; 350 1.1 rkujawa uint16_t tcr; 351 1.1 rkujawa 352 1.1 rkujawa tcr = bus_space_read_2(b->bst, b->bsh, SDMA_TCR_TASK(task)); 353 1.1 rkujawa bus_space_write_2(b->bst, b->bsh, SDMA_TCR_TASK(task), 354 1.1 rkujawa tcr | SDMA_TCR_ENABLE); 355 1.1 rkujawa } 356 1.1 rkujawa 357 1.1 rkujawa void 358 1.1 rkujawa bestcomm_task_stop(int task) 359 1.1 rkujawa { 360 1.1 rkujawa struct bestcomm_ops *b = &bestcomm_sc->sc_pic; 361 1.1 rkujawa uint16_t tcr; 362 1.1 rkujawa 363 1.1 rkujawa tcr = bus_space_read_2(b->bst, b->bsh, SDMA_TCR_TASK(task)); 364 1.1 rkujawa bus_space_write_2(b->bst, b->bsh, SDMA_TCR_TASK(task), 365 1.1 rkujawa tcr & ~SDMA_TCR_ENABLE); 366 1.1 rkujawa } 367 1.1 rkujawa 368 1.1 rkujawa int 369 1.1 rkujawa bestcomm_task_irq(int task) 370 1.1 rkujawa { 371 1.1 rkujawa return bestcomm_sc->sc_pic.pic.pic_intrbase + task; 372 1.1 rkujawa } 373 1.1 rkujawa 374 1.1 rkujawa uint32_t 375 1.1 rkujawa bestcomm_intpend(void) 376 1.1 rkujawa { 377 1.1 rkujawa return sdma_read(&bestcomm_sc->sc_pic, SDMA_INT_PEND); 378 1.1 rkujawa } 379 1.1 rkujawa 380 1.1 rkujawa uint16_t 381 1.1 rkujawa bestcomm_task_tcr(int task) 382 1.1 rkujawa { 383 1.1 rkujawa struct bestcomm_ops *b = &bestcomm_sc->sc_pic; 384 1.1 rkujawa 385 1.1 rkujawa return bus_space_read_2(b->bst, b->bsh, SDMA_TCR_TASK(task)); 386 1.1 rkujawa } 387 1.1 rkujawa 388 1.1 rkujawa /* 389 1.1 rkujawa * Load the task microcode image into SRAM and point the engine at it. 390 1.1 rkujawa */ 391 1.1 rkujawa static void 392 1.1 rkujawa bestcomm_load_image(device_t self) 393 1.1 rkujawa { 394 1.1 rkujawa struct bestcomm_softc *sc = device_private(self); 395 1.1 rkujawa struct bestcomm_ops *b = &sc->sc_pic; 396 1.1 rkujawa struct bestcomm_tdt *tdt; 397 1.1 rkujawa bus_addr_t pa; 398 1.1 rkujawa void *kva; 399 1.1 rkujawa uint32_t i; 400 1.1 rkujawa 401 1.1 rkujawa if (!sram_available()) { 402 1.1 rkujawa aprint_error_dev(self, "no SRAM; SDMA image not loaded\n"); 403 1.1 rkujawa return; 404 1.1 rkujawa } 405 1.1 rkujawa 406 1.1 rkujawa pa = sram_alloc(bestcomm_image_bytes, BESTCOMM_TASKBAR_ALIGN); 407 1.1 rkujawa if (pa == 0) { 408 1.1 rkujawa aprint_error_dev(self, "no SRAM space for %u-byte SDMA image\n", 409 1.1 rkujawa bestcomm_image_bytes); 410 1.1 rkujawa return; 411 1.1 rkujawa } 412 1.1 rkujawa kva = sram_kva(pa); 413 1.1 rkujawa 414 1.1 rkujawa memcpy(kva, bestcomm_image, bestcomm_image_bytes); 415 1.1 rkujawa 416 1.1 rkujawa /* Relocate each task descriptor's pointer words by the TaskBar base. */ 417 1.1 rkujawa tdt = (struct bestcomm_tdt *)((char *)kva + bestcomm_image_entry); 418 1.1 rkujawa for (i = 0; i < bestcomm_image_ntasks; i++) { 419 1.1 rkujawa tdt[i].tdt_start += pa; 420 1.1 rkujawa tdt[i].tdt_stop += pa; 421 1.1 rkujawa tdt[i].tdt_var += pa; 422 1.1 rkujawa tdt[i].tdt_fdt = (pa & 0xffffff00) + tdt[i].tdt_fdt; 423 1.1 rkujawa tdt[i].tdt_context += pa; 424 1.1 rkujawa } 425 1.1 rkujawa 426 1.1 rkujawa sc->sc_taskbar = pa; 427 1.1 rkujawa sc->sc_image_kva = kva; 428 1.1 rkujawa sdma_write(b, SDMA_TASKBAR, pa); 429 1.1 rkujawa 430 1.1 rkujawa aprint_normal_dev(self, 431 1.1 rkujawa "loaded %u-task SDMA image (%u bytes) at SRAM 0x%08jx\n", 432 1.1 rkujawa bestcomm_image_ntasks, bestcomm_image_bytes, (uintmax_t)pa); 433 1.1 rkujawa } 434 1.1 rkujawa 435 1.1 rkujawa /* 436 1.1 rkujawa * Secondary PIC for the 16 task-completion events. 437 1.1 rkujawa */ 438 1.1 rkujawa static void 439 1.1 rkujawa bestcomm_enable_irq(struct pic_ops *pic, int irq, int type) 440 1.1 rkujawa { 441 1.1 rkujawa struct bestcomm_ops *b = pic->pic_cookie; 442 1.1 rkujawa 443 1.1 rkujawa b->int_mask &= ~SDMA_INT_TASK(irq); 444 1.1 rkujawa sdma_write(b, SDMA_INT_MASK, b->int_mask); 445 1.1 rkujawa } 446 1.1 rkujawa 447 1.1 rkujawa static void 448 1.1 rkujawa bestcomm_disable_irq(struct pic_ops *pic, int irq) 449 1.1 rkujawa { 450 1.1 rkujawa struct bestcomm_ops *b = pic->pic_cookie; 451 1.1 rkujawa 452 1.1 rkujawa b->int_mask |= SDMA_INT_TASK(irq); 453 1.1 rkujawa sdma_write(b, SDMA_INT_MASK, b->int_mask); 454 1.1 rkujawa } 455 1.1 rkujawa 456 1.1 rkujawa static int 457 1.1 rkujawa bestcomm_get_irq(struct pic_ops *pic, int mode) 458 1.1 rkujawa { 459 1.1 rkujawa struct bestcomm_ops *b = pic->pic_cookie; 460 1.1 rkujawa uint32_t pending; 461 1.1 rkujawa 462 1.1 rkujawa pending = sdma_read(b, SDMA_INT_PEND) & ~b->int_mask & 463 1.1 rkujawa SDMA_INT_TASK_MASK; 464 1.1 rkujawa if (pending == 0) 465 1.1 rkujawa return 255; 466 1.1 rkujawa 467 1.1 rkujawa return ffs(pending) - 1; /* lowest-numbered pending task */ 468 1.1 rkujawa } 469 1.1 rkujawa 470 1.1 rkujawa static void 471 1.1 rkujawa bestcomm_ack_irq(struct pic_ops *pic, int irq) 472 1.1 rkujawa { 473 1.1 rkujawa struct bestcomm_ops *b = pic->pic_cookie; 474 1.1 rkujawa 475 1.1 rkujawa /* IntPend is write-1-to-clear. */ 476 1.1 rkujawa sdma_write(b, SDMA_INT_PEND, SDMA_INT_TASK(irq)); 477 1.1 rkujawa } 478 1.1 rkujawa 479 1.1 rkujawa static void 480 1.1 rkujawa bestcomm_establish_irq(struct pic_ops *pic, int irq, int type, int maxlevel) 481 1.1 rkujawa { 482 1.1 rkujawa /* Per-task priority is left at its reset default for now. */ 483 1.1 rkujawa } 484 1.1 rkujawa 485