Ejemplo n.º 1
0
void
at91spi_sched(struct at91spi_softc *sc)
{
	struct spi_transfer	*st;
	int			err;

	while ((st = spi_transq_first(&sc->sc_q)) != NULL) {

		DPRINTFN(2, ("%s: st=%p\n", __FUNCTION__, st));

		/* remove the item */
		spi_transq_dequeue(&sc->sc_q);

		/* note that we are working on it */
		sc->sc_transfer = st;

		if ((err = at91spi_select(sc, st->st_slave)) != 0) {
			spi_done(st, err);
			continue;
		}

		/* setup chunks */
		sc->sc_rchunk = sc->sc_wchunk = st->st_chunks;

		/* now kick the master start to get the chip running */
		at91spi_xfer(sc, TRUE);

		/* enable error interrupts too: */
		PUTREG(sc, SPI_IER, SPI_SR_MODF | SPI_SR_OVRES);

		sc->sc_running = TRUE;
		return;
	}
	DPRINTFN(2, ("%s: nothing to do anymore\n", __FUNCTION__));
	PUTREG(sc, SPI_IDR, -1);	/* disable interrupts */
	at91spi_select(sc, -1);
	sc->sc_running = FALSE;
}
Ejemplo n.º 2
0
static int copy_sc_to_user(struct sigcontext __user *to,
			   struct _fpstate __user *to_fp, struct pt_regs *regs,
			   unsigned long mask, unsigned long sp)
{
	struct faultinfo * fi = &current->thread.arch.faultinfo;
	struct user_i387_struct fp;
	int err = 0;

	err |= __put_user(0, &to->gs);
	err |= __put_user(0, &to->fs);

#define PUTREG(regs, regno, sc, regname)				\
	__put_user((regs)->regs.gp[(regno) / sizeof(unsigned long)],	\
		   &(sc)->regname)

	err |= PUTREG(regs, RDI, to, di);
	err |= PUTREG(regs, RSI, to, si);
	err |= PUTREG(regs, RBP, to, bp);
	/*
	 * Must use original RSP, which is passed in, rather than what's in
	 * the pt_regs, because that's already been updated to point at the
	 * signal frame.
	 */
	err |= __put_user(sp, &to->sp);
	err |= PUTREG(regs, RBX, to, bx);
	err |= PUTREG(regs, RDX, to, dx);
	err |= PUTREG(regs, RCX, to, cx);
	err |= PUTREG(regs, RAX, to, ax);
	err |= PUTREG(regs, R8, to, r8);
	err |= PUTREG(regs, R9, to, r9);
	err |= PUTREG(regs, R10, to, r10);
	err |= PUTREG(regs, R11, to, r11);
	err |= PUTREG(regs, R12, to, r12);
	err |= PUTREG(regs, R13, to, r13);
	err |= PUTREG(regs, R14, to, r14);
	err |= PUTREG(regs, R15, to, r15);
	err |= PUTREG(regs, CS, to, cs); /* XXX x86_64 doesn't do this */

	err |= __put_user(fi->cr2, &to->cr2);
	err |= __put_user(fi->error_code, &to->err);
	err |= __put_user(fi->trap_no, &to->trapno);

	err |= PUTREG(regs, RIP, to, ip);
	err |= PUTREG(regs, EFLAGS, to, flags);
#undef PUTREG

	err |= __put_user(mask, &to->oldmask);
	if (err)
		return 1;

	err = save_fp_registers(userspace_pid[current_thread_info()->cpu],
				(unsigned long *) &fp);
	if (err < 0) {
		printk(KERN_ERR "copy_sc_from_user - restore_fp_registers "
		       "failed, errno = %d\n", -err);
		return 1;
	}

	if (copy_to_user(to_fp, &fp, sizeof(struct user_i387_struct)))
		return 1;

	return err;
}
Ejemplo n.º 3
0
Archivo: isrs.c Proyecto: charles-l/ix
void fault_handler(struct regs *r)
{
    if (r->int_no < 32)
    {
        putch('\n');
        kputs("-- BEGIN KERNEL PANIC --\n");
        PUTREG(ds);
        PUTREG(edi); PUTREG(esi); PUTREG(ebp); PUTREG(esp);
        PUTREG(ebx); PUTREG(edx); PUTREG(ecx); PUTREG(eax);
        PUTREG(eip); PUTREG(cs); PUTREG(eflags); PUTREG(useresp); PUTREG(ss);
        PUTREG(err_code);
        kputs("\n");
        kputs(exception_messages[r->int_no]);
        kputs(" exception!!! SYSTEM HALTED!\n");
        for(;;);
    }
}
Ejemplo n.º 4
0
int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp,
                        struct pt_regs *regs, unsigned long mask)
{
        struct faultinfo * fi = &current->thread.arch.faultinfo;
	int err = 0;

	err |= __put_user(0, &to->gs);
	err |= __put_user(0, &to->fs);

#define PUTREG(regs, regno, sc, regname) \
       __put_user((regs)->regs.skas.regs[(regno) / sizeof(unsigned long)], \
                  &(sc)->regname)

	err |= PUTREG(regs, RDI, to, rdi);
	err |= PUTREG(regs, RSI, to, rsi);
	err |= PUTREG(regs, RBP, to, rbp);
	err |= PUTREG(regs, RSP, to, rsp);
	err |= PUTREG(regs, RBX, to, rbx);
	err |= PUTREG(regs, RDX, to, rdx);
	err |= PUTREG(regs, RCX, to, rcx);
	err |= PUTREG(regs, RAX, to, rax);
	err |= PUTREG(regs, R8, to, r8);
	err |= PUTREG(regs, R9, to, r9);
	err |= PUTREG(regs, R10, to, r10);
	err |= PUTREG(regs, R11, to, r11);
	err |= PUTREG(regs, R12, to, r12);
	err |= PUTREG(regs, R13, to, r13);
	err |= PUTREG(regs, R14, to, r14);
	err |= PUTREG(regs, R15, to, r15);
	err |= PUTREG(regs, CS, to, cs); /* XXX x86_64 doesn't do this */

        err |= __put_user(fi->cr2, &to->cr2);
        err |= __put_user(fi->error_code, &to->err);
        err |= __put_user(fi->trap_no, &to->trapno);

	err |= PUTREG(regs, RIP, to, rip);
	err |= PUTREG(regs, EFLAGS, to, eflags);
#undef PUTREG

	err |= __put_user(mask, &to->oldmask);

	return(err);
}
Ejemplo n.º 5
0
void
at91spi_xfer(struct at91spi_softc *sc, int start)
{
	struct spi_chunk	*chunk;
	int			len;
	uint32_t		sr;

	DPRINTFN(3, ("%s: sc=%p start=%d\n", __FUNCTION__, sc, start));

	/* so ready to transmit more / anything received? */
	if (((sr = GETREG(sc, SPI_SR)) & (SPI_SR_ENDTX | SPI_SR_ENDRX)) != (SPI_SR_ENDTX | SPI_SR_ENDRX)) {
		/* not ready, get out */
		DPRINTFN(3, ("%s: sc=%p start=%d sr=%"PRIX32"\n", __FUNCTION__, sc, start, sr));
		return;
	}

	DPRINTFN(3, ("%s: sr=%"PRIX32"\n", __FUNCTION__, sr));

	if (!start) {
		// ok, something has been transfered, synchronize..
		int offs = sc->sc_dmaoffs ^ HALF_BUF_SIZE;
		bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, offs, HALF_BUF_SIZE,
				BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);

		if ((chunk = sc->sc_rchunk) != NULL) {
			if ((len = chunk->chunk_rresid) > HALF_BUF_SIZE)
				len = HALF_BUF_SIZE;
			if (chunk->chunk_rptr && len > 0) {
				memcpy(chunk->chunk_rptr, (const uint8_t *)sc->sc_dmapage + offs, len);
				chunk->chunk_rptr += len;
			}
			if ((chunk->chunk_rresid -= len) <= 0) {
				// done with this chunk, get next
				sc->sc_rchunk = chunk->chunk_next;
			}
		}
	}

	/* start transmitting next chunk: */
	if ((chunk = sc->sc_wchunk) != NULL) {

		/* make sure we transmit just half buffer at a time */
		len = MIN(chunk->chunk_wresid, HALF_BUF_SIZE);

		// setup outgoing data
		if (chunk->chunk_wptr && len > 0) {
			memcpy((uint8_t *)sc->sc_dmapage + sc->sc_dmaoffs, chunk->chunk_wptr, len);
			chunk->chunk_wptr += len;
		} else {
			memset((uint8_t *)sc->sc_dmapage + sc->sc_dmaoffs, 0, len);
		}

		/* advance to next transfer if it's time to */
		if ((chunk->chunk_wresid -= len) <= 0) {
			sc->sc_wchunk = sc->sc_wchunk->chunk_next;
		}

		/* determine which interrupt to get */
		if (sc->sc_wchunk) {
			/* just wait for next buffer to free */
			PUTREG(sc, SPI_IER, SPI_SR_ENDRX);
		} else {
			/* must wait until transfer has completed */
			PUTREG(sc, SPI_IDR, SPI_SR_ENDRX);
			PUTREG(sc, SPI_IER, SPI_SR_RXBUFF);
		}

		DPRINTFN(3, ("%s: dmaoffs=%d len=%d wchunk=%p (%p:%d) rchunk=%p (%p:%d) mr=%"PRIX32" sr=%"PRIX32" imr=%"PRIX32" csr0=%"PRIX32"\n",
			     __FUNCTION__, sc->sc_dmaoffs, len, sc->sc_wchunk,
			     sc->sc_wchunk ? sc->sc_wchunk->chunk_wptr : NULL,
			     sc->sc_wchunk ? sc->sc_wchunk->chunk_wresid : -1,
			     sc->sc_rchunk,
			     sc->sc_rchunk ? sc->sc_rchunk->chunk_rptr : NULL,
			     sc->sc_rchunk ? sc->sc_rchunk->chunk_rresid : -1,
			     GETREG(sc, SPI_MR), GETREG(sc, SPI_SR), 
			     GETREG(sc, SPI_IMR), GETREG(sc, SPI_CSR(0))));

		// prepare DMA
		bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, sc->sc_dmaoffs, len,
				BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);

		// and start transmitting / receiving
		PUTREG(sc, SPI_PDC_BASE + PDC_RNPR, sc->sc_dmaaddr + sc->sc_dmaoffs);
		PUTREG(sc, SPI_PDC_BASE + PDC_RNCR, len);
		PUTREG(sc, SPI_PDC_BASE + PDC_TNPR, sc->sc_dmaaddr + sc->sc_dmaoffs);
		PUTREG(sc, SPI_PDC_BASE + PDC_TNCR, len);

		// swap buffer
		sc->sc_dmaoffs ^= HALF_BUF_SIZE;

		// get out
		return;
	} else {
		DPRINTFN(3, ("%s: nothing to write anymore\n", __FUNCTION__));
		return;
	}
}
Ejemplo n.º 6
0
int
at91spi_configure(void *arg, int slave, int mode, int speed)
{
	struct at91spi_softc *sc = arg;
	uint		scbr;
	uint32_t	csr;

	/* setup interrupt registers */
	PUTREG(sc, SPI_IDR, -1);	/* disable interrupts for now	*/

	csr = GETREG(sc, SPI_CSR(0));	/* read register		*/
	csr &= SPI_CSR_RESERVED;	/* keep reserved bits		*/
	csr |= SPI_CSR_BITS_8;		/* assume 8 bit transfers	*/

	/*
	 * Calculate clock divider
	 */
	scbr = speed ? ((AT91_MSTCLK + speed - 1) / speed + 1) & ~1 : -1;
	if (scbr > 0xFF) {
		aprint_error("%s: speed %d not supported\n",
		    device_xname(sc->sc_dev), speed);
		return EINVAL;
	}
	csr |= scbr << SPI_CSR_SCBR_SHIFT;

	/*
	 * I'm not entirely confident that these values are correct.
	 * But at least mode 0 appears to work properly with the
	 * devices I have tested.  The documentation seems to suggest
	 * that I have the meaning of the clock delay bit inverted.
	 */
	switch (mode) {
	case SPI_MODE_0:
		csr |= SPI_CSR_NCPHA;		/* CPHA = 0, CPOL = 0 */
		break;
	case SPI_MODE_1:
		csr |= 0;			/* CPHA = 1, CPOL = 0 */
		break;
	case SPI_MODE_2:
		csr |= SPI_CSR_NCPHA		/* CPHA = 0, CPOL = 1 */
		       | SPI_CSR_CPOL;
		break;
	case SPI_MODE_3:
		csr |= SPI_CSR_CPOL;		/* CPHA = 1, CPOL = 1 */
		break;
	default:
		return EINVAL;
	}

	PUTREG(sc, SPI_CSR(0), csr);

	DPRINTFN(3, ("%s: slave %d mode %d speed %d, csr=0x%08"PRIX32"\n",
		     __FUNCTION__, slave, mode, speed, csr));

#if 0
	// wait until ready!?
	for (i = 1000000; i; i -= 10) {
		if (GETREG(sc, AUPSC_SPISTAT) & SPISTAT_DR) {
			return 0;
		}
	}

	return ETIMEDOUT;
#else
	return 0;
#endif
}
Ejemplo n.º 7
0
void
at91spi_attach_common(device_t parent, device_t self, void *aux,
		      at91spi_machdep_tag_t md)
{
	struct at91spi_softc *sc = device_private(self);
	struct at91bus_attach_args *sa = aux;
	struct spibus_attach_args sba;
	bus_dma_segment_t segs;
	int rsegs, err;

	aprint_normal(": AT91 SPI Controller\n");

	sc->sc_dev = self;
	sc->sc_iot = sa->sa_iot;
	sc->sc_pid = sa->sa_pid;
	sc->sc_dmat = sa->sa_dmat;
	sc->sc_md = md;

	if (bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 0, &sc->sc_ioh))
		panic("%s: Cannot map registers", device_xname(self));

	/* we want to use dma, so allocate dma memory: */
	err = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, 0, PAGE_SIZE,
			       &segs, 1, &rsegs, BUS_DMA_WAITOK);
	if (err == 0) {
		err = bus_dmamem_map(sc->sc_dmat, &segs, 1, PAGE_SIZE,
				     &sc->sc_dmapage,
				     BUS_DMA_WAITOK);
	}
	if (err == 0) {
		err = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1,
					 PAGE_SIZE, 0, BUS_DMA_WAITOK,
					 &sc->sc_dmamap);
	}
	if (err == 0) {
		err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap,
				      sc->sc_dmapage, PAGE_SIZE, NULL,
				      BUS_DMA_WAITOK);
	}
	if (err != 0) {
		panic("%s: Cannot get DMA memory", device_xname(sc->sc_dev));
	}
	sc->sc_dmaaddr = sc->sc_dmamap->dm_segs[0].ds_addr;

	/*
	 * Initialize SPI controller
	 */
	sc->sc_spi.sct_cookie = sc;
	sc->sc_spi.sct_configure = at91spi_configure;
	sc->sc_spi.sct_transfer = at91spi_transfer;

	//sc->sc_spi.sct_nslaves must have been initialized by machdep code
	if (!sc->sc_spi.sct_nslaves) {
		aprint_error("%s: no slaves!\n", device_xname(sc->sc_dev));
	}

	sba.sba_controller = &sc->sc_spi;

	/* initialize the queue */
	SIMPLEQ_INIT(&sc->sc_q);

	/* reset the SPI */
	at91_peripheral_clock(sc->sc_pid, 1);
	PUTREG(sc, SPI_CR, SPI_CR_SWRST);
	delay(100);

	/* be paranoid and make sure the PDC is dead */
	PUTREG(sc, SPI_PDC_BASE + PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS);
	PUTREG(sc, SPI_PDC_BASE + PDC_RNCR, 0);
	PUTREG(sc, SPI_PDC_BASE + PDC_RCR, 0);
	PUTREG(sc, SPI_PDC_BASE + PDC_TNCR, 0);
	PUTREG(sc, SPI_PDC_BASE + PDC_TCR, 0);

	// configure SPI:
	PUTREG(sc, SPI_IDR, -1);
	PUTREG(sc, SPI_CSR(0), SPI_CSR_SCBR | SPI_CSR_BITS_8);
	PUTREG(sc, SPI_CSR(1), SPI_CSR_SCBR | SPI_CSR_BITS_8);
	PUTREG(sc, SPI_CSR(2), SPI_CSR_SCBR | SPI_CSR_BITS_8);
	PUTREG(sc, SPI_CSR(3), SPI_CSR_SCBR | SPI_CSR_BITS_8);
	PUTREG(sc, SPI_MR, SPI_MR_MODFDIS/* <- machdep? */ | SPI_MR_MSTR);

	/* enable device interrupts */
	sc->sc_ih = at91_intr_establish(sc->sc_pid, IPL_BIO, INTR_HIGH_LEVEL,
					at91spi_intr, sc);

	/* enable SPI */
	PUTREG(sc, SPI_CR, SPI_CR_SPIEN);
	if (GETREG(sc, SPI_SR) & SPI_SR_RDRF)
		(void)GETREG(sc, SPI_RDR);

	PUTREG(sc, SPI_PDC_BASE + PDC_PTCR, PDC_PTCR_TXTEN | PDC_PTCR_RXTEN);

	/* attach slave devices */
	(void) config_found_ia(sc->sc_dev, "spibus", &sba, spibus_print);
}