Пример #1
0
/* Commit and/or discard all DMA descriptors and buffers pointed by them,
 * handle circular lists. At the same time, convert virtual pointers to
 * real ones */
static void dma_commit_and_discard(unsigned chan, struct apb_dma_command_t *cmd)
{
    /* We handle circular descriptors by using unused bits:
     * bits 8-11 are not used by the hardware so we first go through the whole
     * list and mark them all a special value at the same time we commit buffers
     * and then we go through the list another time to clear the mark and
     * commit the descriptors */
    struct apb_dma_command_t *cur = cmd;

    while((cur->cmd & HW_APB_CHx_CMD__UNUSED_BM) != HW_APB_CHx_CMD__UNUSED_MAGIC)
    {
        cur->cmd = (cur->cmd & ~HW_APB_CHx_CMD__UNUSED_BM) | HW_APB_CHx_CMD__UNUSED_MAGIC;
        int op = cur->cmd & HW_APB_CHx_CMD__COMMAND_BM;
        int sz = __XTRACT_EX(cur->cmd, HW_APB_CHx_CMD__XFER_COUNT);
        /* device > host: discard */
        if(op == HW_APB_CHx_CMD__COMMAND__WRITE)
            discard_dcache_range(cur->buffer, sz);
        /* host > device: commit and discard */
        else if(op == HW_APB_CHx_CMD__COMMAND__READ)
            commit_discard_dcache_range(cur->buffer, sz);
        if((uint32_t)cur->buffer % CACHEALIGN_SIZE)
            apb_nr_unaligned[chan]++;
        /* Virtual to physical buffer pointer conversion */
        cur->buffer = PHYSICAL_ADDR(cur->buffer);
        /* chain ? */
        if(cur->cmd & HW_APB_CHx_CMD__CHAIN)
            cur = cur->next;
        else
            break;
    }

    cur = cmd;
    while((cur->cmd & HW_APB_CHx_CMD__UNUSED_BM) != 0)
    {
        cur->cmd = cur->cmd & ~HW_APB_CHx_CMD__UNUSED_BM;
        int sz = __XTRACT_EX(cur->cmd, HW_APB_CHx_CMD__CMDWORDS) * sizeof(uint32_t);
        /* commit descriptor and discard descriptor */
        /* chain ? */
        if(cur->cmd & HW_APB_CHx_CMD__CHAIN)
        {
            struct apb_dma_command_t *next = cur->next;
            cur->next = PHYSICAL_ADDR(cur->next);
            commit_dcache_range(cur, sizeof(struct apb_dma_command_t) + sz);
            cur = next;
        }
        else
        {
            commit_dcache_range(cur, sizeof(struct apb_dma_command_t) + sz);
            break;
        }
    }
}
Пример #2
0
void dma_start_command(unsigned chan, struct apb_dma_command_t *cmd)
{
    dma_commit_and_discard(chan, cmd);
    if(APB_IS_APBX_CHANNEL(chan))
    {
        HW_APBX_CHx_NXTCMDAR(APB_GET_DMA_CHANNEL(chan)) = (uint32_t)PHYSICAL_ADDR(cmd);
        HW_APBX_CHx_SEMA(APB_GET_DMA_CHANNEL(chan)) = 1;
    }
    else
    {
        HW_APBH_CHx_NXTCMDAR(APB_GET_DMA_CHANNEL(chan)) = (uint32_t)PHYSICAL_ADDR(cmd);
        HW_APBH_CHx_SEMA(APB_GET_DMA_CHANNEL(chan)) = 1;
    }
}
Пример #3
0
static void ep_transfer(int ep, void *ptr, int len, bool out)
{
    /* disable interrupts to avoid any race */
    int oldlevel = disable_irq_save();

    struct ep_type *endpoint = &endpoints[ep][out ? DIR_OUT : DIR_IN];
    endpoint->busy   = true;
    endpoint->size   = len;
    endpoint->status = -1;

    if (out)
        DEPCTL(ep, out) &= ~DEPCTL_stall;

    int mps = usb_drv_port_speed() ? 512 : 64;
    int nb_packets = (len + mps - 1) / mps;
    if (nb_packets == 0)
        nb_packets = 1;

    DEPDMA(ep, out) = len ? (void*)PHYSICAL_ADDR(ptr) : NULL;
    DEPTSIZ(ep, out) = (nb_packets << DEPTSIZ_pkcnt_bitp) | len;
    if(out)
        discard_dcache_range(ptr, len);
    else
        commit_dcache_range(ptr, len);

    logf("pkt=%d dma=%lx", nb_packets, DEPDMA(ep, out));

//    if (!out) while (((GNPTXSTS & 0xffff) << 2) < MIN(mps, length));

    DEPCTL(ep, out) |= DEPCTL_epena | DEPCTL_cnak;

    restore_irq(oldlevel);
}
Пример #4
0
static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz)
{
	uint32_t delta, next;
	uint32_t addr = (uint32_t)buf;
	size_t rsz = roundup(sz, 32);
	int idx;

	if (sz != rsz)
		debug("EHCI-HCD: Misaligned buffer size (%08x)\n", sz);

	if (addr & 31)
		debug("EHCI-HCD: Misaligned buffer address (%p)\n", buf);

	idx = 0;
	while (idx < 5) {
		flush_dcache_range(addr, addr + rsz);
		td->qt_buffer[idx] = cpu_to_hc32(PHYSICAL_ADDR(addr));
		td->qt_buffer_hi[idx] = 0;
		next = (addr + 4096) & ~4095;
		delta = next - addr;
		if (delta >= sz)
			break;
		sz -= delta;
		addr = next;
		idx++;
	}

	if (idx == 5) {
		debug("out of buffer pointers (%u bytes left)\n", sz);
		return -1;
	}

	return 0;
}
Пример #5
0
static enum imx233_dcp_error_t imx233_dcp_job(int ch)
{
    /* if IRQs are not enabled, don't enable channel interrupt and do some polling */
    bool irq_enabled = irq_enabled();
    /* enable channel, clear interrupt, enable interrupt */
    imx233_icoll_enable_interrupt(INT_SRC_DCP, true);
    if(irq_enabled)
        __REG_SET(HW_DCP_CTRL) = HW_DCP_CTRL__CHANNEL_INTERRUPT_ENABLE(ch);
    __REG_CLR(HW_DCP_STAT) = HW_DCP_STAT__IRQ(ch);
    __REG_SET(HW_DCP_CHANNELCTRL) = HW_DCP_CHANNELCTRL__ENABLE_CHANNEL(ch);

    /* write back packet */
    commit_discard_dcache_range(&channel_packet[ch], sizeof(struct imx233_dcp_packet_t));
    /* write 1 to semaphore to run job */
    HW_DCP_CHxCMDPTR(ch) = (uint32_t)PHYSICAL_ADDR(&channel_packet[ch]);
    HW_DCP_CHxSEMA(ch) = 1;
    /* wait completion */
    if(irq_enabled)
        semaphore_wait(&channel_sema[ch], TIMEOUT_BLOCK);
    else
        while(__XTRACT_EX(HW_DCP_CHxSEMA(ch), HW_DCP_CHxSEMA__VALUE))
            udelay(10);
    /* disable channel and interrupt */
    __REG_CLR(HW_DCP_CTRL) = HW_DCP_CTRL__CHANNEL_INTERRUPT_ENABLE(ch);
    __REG_CLR(HW_DCP_CHANNELCTRL) = HW_DCP_CHANNELCTRL__ENABLE_CHANNEL(ch);
    /* read status */
    return get_error_status(ch);
}
Пример #6
0
// Handle select DOS interrupt 21h services.
void Int21h(int intNum)
{
	char *string;
	unsigned int i;
	unsigned int maxi;
	int length;

	switch(M.x86.R_AH) {
	case 0x02:	// Character output. DL is 8-bit character to print
		ProgramWindow->PrintChar(M.x86.R_DL);
		break;

	case 0x09:	// String output. DS:DX points to '$' terminated string
		string = (char *)M.privatevp;
		i = PHYSICAL_ADDR(M.x86.R_DS, M.x86.R_DX);

		for(maxi = i; string[maxi] != '$' && maxi < M.mem_size; maxi++);
		length = maxi - i;

		if(length > 0) ProgramWindow->SendString(string + i, length);
		
		break;
	
	case 0x40:	// Write to device or file. Only supports deivce 0x01 (stdout). BX is handle, CX is num bytes, DS:DX points to data to write.
		if(M.x86.R_BX != 1) {
			ProgramWindow->PrintText("ERROR: Only handle 1 (stdout) supported for INT 21h, service 40h. Handle %Xh was requested.\n", M.x86.R_BX);
			break;
		}

		i = PHYSICAL_ADDR(M.x86.R_DS, M.x86.R_DX);
		length = M.x86.R_CX;
		if(i + length >= M.mem_size) length = M.mem_size - i;
		
		if(length > 0) ProgramWindow->SendString((char *)M.privatevp + i, length);
		
		break;

	case 0x4C:	// Terminate with return code. AL is return code
		SimControl->ProgramTerminated((int)(M.x86.R_AL));
		break;

	default:
		ProgramWindow->PrintText("ERROR: INT 21h, service %xh not supported.\n", (unsigned)M.x86.R_AH);
	}
}
Пример #7
0
static void prepare_setup_ep0(void)
{
    DEPDMA(0, true) = (void*)PHYSICAL_ADDR(&_ep0_setup_pkt);
    DEPTSIZ(0, true) = (1 << DEPTSIZ0_supcnt_bitp)
                | (1 << DEPTSIZ0_pkcnt_bitp)
                | 8;
    DEPCTL(0, true) |= DEPCTL_epena | DEPCTL_cnak;

    ep0_state = EP0_WAIT_SETUP;
}
Пример #8
0
enum imx233_dcp_error_t imx233_dcp_blit_ex(int ch, bool fill, const void *src, size_t w, size_t h, void *dst, size_t out_w)
{
    /* prepare packet */
    channel_packet[ch].next = 0;
    channel_packet[ch].ctrl0 = HW_DCP_CTRL0__INTERRUPT_ENABLE |
    HW_DCP_CTRL0__ENABLE_MEMCOPY | HW_DCP_CTRL0__DECR_SEMAPHORE |
    HW_DCP_CTRL0__ENABLE_BLIT |
    (fill ? HW_DCP_CTRL0__CONSTANT_FILL : 0);
    channel_packet[ch].ctrl1 = out_w;
    channel_packet[ch].src = (uint32_t)(fill ? src : PHYSICAL_ADDR(src));
    channel_packet[ch].dst = (uint32_t)PHYSICAL_ADDR(dst);
    channel_packet[ch].size = w | h << HW_DCP_SIZE__NUMBER_LINES_BP;
    channel_packet[ch].payload = 0;
    channel_packet[ch].status = 0;
    
    /* we have a problem here to discard the output buffer since it's not contiguous
     * so only commit the source */
    if(!fill)
        commit_discard_dcache_range(src, w * h);
    /* do the job */
    return imx233_dcp_job(ch);
}
Пример #9
0
enum imx233_dcp_error_t imx233_dcp_memcpy_ex(int ch, bool fill, const void *src, void *dst, size_t len)
{
    /* prepare packet */
    channel_packet[ch].next = 0;
    channel_packet[ch].ctrl0 = HW_DCP_CTRL0__INTERRUPT_ENABLE |
        HW_DCP_CTRL0__ENABLE_MEMCOPY | HW_DCP_CTRL0__DECR_SEMAPHORE |
        (fill ? HW_DCP_CTRL0__CONSTANT_FILL : 0);
    channel_packet[ch].ctrl1 = 0;
    channel_packet[ch].src = (uint32_t)(fill ? src : PHYSICAL_ADDR(src));
    channel_packet[ch].dst = (uint32_t)PHYSICAL_ADDR(dst);
    channel_packet[ch].size = len;
    channel_packet[ch].payload = 0;
    channel_packet[ch].status = 0;

    /* write-back src if not filling, discard dst */
    if(!fill)
        commit_discard_dcache_range(src, len);
    discard_dcache_range(dst, len);

    /* do the job */
    return imx233_dcp_job(ch);
}
Пример #10
0
void imx233_dcp_init(void)
{
    /* Reset block */
    imx233_reset_block(&HW_DCP_CTRL);
    /* Setup contexte pointer */
    HW_DCP_CONTEXT = (uint32_t)PHYSICAL_ADDR(&dcp_context);
    /* Enable context switching and caching */
    __REG_SET(HW_DCP_CTRL) = HW_DCP_CTRL__ENABLE_CONTEXT_CACHING |
        HW_DCP_CTRL__ENABLE_CONTEXT_SWITCHING;
    /* Check that there are sufficiently many channels */
    if(__XTRACT(HW_DCP_CAPABILITY0, NUM_CHANNELS) != HW_DCP_NUM_CHANNELS)
        panicf("DCP has %lu channels but was configured to use %d !",
               __XTRACT(HW_DCP_CAPABILITY0, NUM_CHANNELS), HW_DCP_NUM_CHANNELS);
    /* Setup channel arbiter to use */
    arbiter_init(&channel_arbiter, HW_DCP_NUM_CHANNELS);
    /* Merge channel0 interrupt */
    __REG_SET(HW_DCP_CHANNELCTRL) = HW_DCP_CHANNELCTRL__CH0_IRQ_MERGED;
    /* setup semaphores */
    for(int i = 0; i< HW_DCP_NUM_CHANNELS; i++)
        semaphore_init(&channel_sema[i], 1, 0);
}
Пример #11
0
// Takes a string representing an Address
// It can be of the following forms:
//  1) seg:off		(hex only for segment and offset)
//  2) 0xAB, 0XAB	(hex)
//  3) ABh, ABH		(hex)
//  3) 171			(decimal assumed)
void InterpretAddress(char *addrString, Address *addr)
{
	int i, len;
	bool isColon;
	char *segmentStr, *offsetStr;
	
	isColon = false;

	// Determin string length
	for(len = 0; addrString[len] != '\0'; len++);

	// Check for HEX segment offset form 0000:0000
	for(i = 0; i < len; i++) {
		if(addrString[i] == ':') {
			isColon = true;
			addrString[i] = '\0';		// Null terminate segment
			segmentStr = &addrString[0];
			offsetStr = &addrString[i+1];
		}
	}
	
	if(isColon) {
		// Of form seg:off. Get the two and calculate physical address.
		//addr->segment = XtoI(segmentStr);
		//addr->offset = XtoI(offsetStr);
		sscanf(segmentStr, "%x", &(addr->segment));
		sscanf(offsetStr, "%x", &(addr->offset));
		addr->physical = PHYSICAL_ADDR(addr->segment, addr->offset);
	}
	else {
		// Single number. Get it and calculate segment and offset.
		addr->physical = InterpretNumber(addrString);
		addr->segment = SEGMENT(addr->physical);
		addr->offset = OFFSET(addr->physical);
	}
}
Пример #12
0
static int
ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
		   int length, struct devrequest *req)
{
	static struct QH qh __attribute__((aligned(32)));
	static struct qTD qtd[3] __attribute__((aligned (32)));
	int qtd_counter = 0;

	volatile struct qTD *vtd;
	unsigned long ts;
	uint32_t *tdp;
	uint32_t endpt, token, usbsts;
	uint32_t c, toggle;
	uint32_t cmd;
	int timeout;
	int ret = 0;

	debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe,
	      buffer, length, req);
	if (req != NULL)
		debug("req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u\n",
		      req->request, req->request,
		      req->requesttype, req->requesttype,
		      le16_to_cpu(req->value), le16_to_cpu(req->value),
		      le16_to_cpu(req->index));

	memset(&qh, 0, sizeof(struct QH));
	memset(qtd, 0, sizeof(qtd));

	toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));

	/*
	 * Setup QH (3.6 in ehci-r10.pdf)
	 *
	 *   qh_link ................. 03-00 H
	 *   qh_endpt1 ............... 07-04 H
	 *   qh_endpt2 ............... 0B-08 H
	 * - qh_curtd
	 *   qh_overlay.qt_next ...... 13-10 H
	 * - qh_overlay.qt_altnext
	 */
	qh.qh_link = cpu_to_hc32((uint32_t)PHYSICAL_ADDR(&qh_list) | QH_LINK_TYPE_QH);
	c = (usb_pipespeed(pipe) != USB_SPEED_HIGH &&
	     usb_pipeendpoint(pipe) == 0) ? 1 : 0;
	endpt = (8 << 28) |
	    (c << 27) |
	    (usb_maxpacket(dev, pipe) << 16) |
	    (0 << 15) |
	    (1 << 14) |
	    (usb_pipespeed(pipe) << 12) |
	    (usb_pipeendpoint(pipe) << 8) |
	    (0 << 7) | (usb_pipedevice(pipe) << 0);
	qh.qh_endpt1 = cpu_to_hc32(endpt);
	endpt = (1 << 30) |
	    (dev->portnr << 23) |
	    (dev->parent->devnum << 16) | (0 << 8) | (0 << 0);
	qh.qh_endpt2 = cpu_to_hc32(endpt);
	qh.qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);

	tdp = &qh.qh_overlay.qt_next;

	if (req != NULL) {
		/*
		 * Setup request qTD (3.5 in ehci-r10.pdf)
		 *
		 *   qt_next ................ 03-00 H
		 *   qt_altnext ............. 07-04 H
		 *   qt_token ............... 0B-08 H
		 *
		 *   [ buffer, buffer_hi ] loaded with "req".
		 */
		qtd[qtd_counter].qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
		qtd[qtd_counter].qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
		token = (0 << 31) |
		    (sizeof(*req) << 16) |
		    (0 << 15) | (0 << 12) | (3 << 10) | (2 << 8) | (0x80 << 0);
		qtd[qtd_counter].qt_token = cpu_to_hc32(token);
		if (ehci_td_buffer(&qtd[qtd_counter], req, sizeof(*req)) != 0) {
			debug("unable construct SETUP td\n");
			goto fail;
		}
		/* Update previous qTD! */
		*tdp = cpu_to_hc32((uint32_t)PHYSICAL_ADDR(&qtd[qtd_counter]));
		tdp = &qtd[qtd_counter++].qt_next;
		toggle = 1;
	}

	if (length > 0 || req == NULL) {
		/*
		 * Setup request qTD (3.5 in ehci-r10.pdf)
		 *
		 *   qt_next ................ 03-00 H
		 *   qt_altnext ............. 07-04 H
		 *   qt_token ............... 0B-08 H
		 *
		 *   [ buffer, buffer_hi ] loaded with "buffer".
		 */
		qtd[qtd_counter].qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
		qtd[qtd_counter].qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
		token = (toggle << 31) |
		    (length << 16) |
		    ((req == NULL ? 1 : 0) << 15) |
		    (0 << 12) |
		    (3 << 10) |
		    ((usb_pipein(pipe) ? 1 : 0) << 8) | (0x80 << 0);
		qtd[qtd_counter].qt_token = cpu_to_hc32(token);
		if (ehci_td_buffer(&qtd[qtd_counter], buffer, length) != 0) {
			debug("unable construct DATA td\n");
			goto fail;
		}
		/* Update previous qTD! */
		*tdp = cpu_to_hc32((uint32_t)PHYSICAL_ADDR(&qtd[qtd_counter]));
		tdp = &qtd[qtd_counter++].qt_next;
	}

	if (req != NULL) {
		/*
		 * Setup request qTD (3.5 in ehci-r10.pdf)
		 *
		 *   qt_next ................ 03-00 H
		 *   qt_altnext ............. 07-04 H
		 *   qt_token ............... 0B-08 H
		 */
		qtd[qtd_counter].qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
		qtd[qtd_counter].qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
		token = (toggle << 31) |
		    (0 << 16) |
		    (1 << 15) |
		    (0 << 12) |
		    (3 << 10) |
		    ((usb_pipein(pipe) ? 0 : 1) << 8) | (0x80 << 0);
		qtd[qtd_counter].qt_token = cpu_to_hc32(token);
		/* Update previous qTD! */
		*tdp = cpu_to_hc32((uint32_t)PHYSICAL_ADDR(&qtd[qtd_counter]));
		tdp = &qtd[qtd_counter++].qt_next;
	}

	qh_list.qh_link = cpu_to_hc32((uint32_t) PHYSICAL_ADDR(&qh) | QH_LINK_TYPE_QH);

	/* Flush dcache */
	flush_dcache_range((uint32_t)&qh_list,
		(uint32_t)&qh_list + sizeof(struct QH));
	flush_dcache_range((uint32_t)&qh, (uint32_t)&qh + sizeof(struct QH));
	flush_dcache_range((uint32_t)qtd, (uint32_t)qtd + sizeof(qtd));

	usbsts = ehci_readl(&hcor->or_usbsts);
	ehci_writel(&hcor->or_usbsts, (usbsts & 0x3f));

	/* Enable async. schedule. */
	cmd = ehci_readl(&hcor->or_usbcmd);
	cmd |= CMD_ASE;
	ehci_writel(&hcor->or_usbcmd, cmd);

	ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, STD_ASS,
			100 * 1000);
	if (ret < 0) {
		printf("EHCI fail timeout STD_ASS set\n");
		goto fail;
	}

	/* Wait for TDs to be processed. */
	ts = get_timer(0);
	vtd = &qtd[qtd_counter - 1];
	timeout = USB_TIMEOUT_MS(pipe);
	do {
		/* Invalidate dcache */
		invalidate_dcache_range((uint32_t)&qh_list,
			(uint32_t)&qh_list + sizeof(struct QH));
		invalidate_dcache_range((uint32_t)&qh,
			(uint32_t)&qh + sizeof(struct QH));
		invalidate_dcache_range((uint32_t)qtd,
			(uint32_t)qtd + sizeof(qtd));

		token = hc32_to_cpu(vtd->qt_token);
		if (!(token & 0x80))
			break;
		WATCHDOG_RESET();
	} while (get_timer(ts) < timeout);

	/* Invalidate the memory area occupied by buffer */
	if (buffer!=NULL) {
		invalidate_dcache_range(((uint32_t)buffer & ~31),
			((uint32_t)buffer & ~31) + roundup(length, 32));
	}

	/* Check that the TD processing happened */
	if (token & 0x80) {
		printf("EHCI timed out on TD - token=%#x\n", token);
	}

	/* Disable async schedule. */
	cmd = ehci_readl(&hcor->or_usbcmd);
	cmd &= ~CMD_ASE;
	ehci_writel(&hcor->or_usbcmd, cmd);

	ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, 0,
			100 * 1000);
	if (ret < 0) {
		printf("EHCI fail timeout STD_ASS reset\n");
		goto fail;
	}

	qh_list.qh_link = cpu_to_hc32((uint32_t)PHYSICAL_ADDR(&qh_list) | QH_LINK_TYPE_QH);

	token = hc32_to_cpu(qh.qh_overlay.qt_token);
	if (!(token & 0x80)) {
		debug("TOKEN=%#x\n", token);
		switch (token & 0xfc) {
		case 0:
			toggle = token >> 31;
			usb_settoggle(dev, usb_pipeendpoint(pipe),
				       usb_pipeout(pipe), toggle);
			dev->status = 0;
			break;
		case 0x40:
			dev->status = USB_ST_STALLED;
			break;
		case 0xa0:
		case 0x20:
			dev->status = USB_ST_BUF_ERR;
			break;
		case 0x50:
		case 0x10:
			dev->status = USB_ST_BABBLE_DET;
			break;
		default:
			dev->status = USB_ST_CRC_ERR;
			if ((token & 0x40) == 0x40)
				dev->status |= USB_ST_STALLED;
			break;
		}
		dev->act_len = length - ((token >> 16) & 0x7fff);
	} else {