Ejemplo n.º 1
0
/*
 * U-Boot USB interface
 */
int usb_lowlevel_init(int index, void **controller)
{
	/*
	 * We need doubleword-aligned buffers for DMA transfers
	 */
	allocated_buffer = (uint8_t *)malloc(DWC_OTG_HCD_STATUS_BUF_SIZE + DWC_OTG_HCD_DATA_BUF_SIZE + 8);
	uint32_t addr = (uint32_t)allocated_buffer;
	aligned_buffer = (uint8_t *) ((addr + 7) & ~7);
	status_buffer = (uint8_t *)((uint32_t)aligned_buffer + DWC_OTG_HCD_DATA_BUF_SIZE);
	int i, j;
	hprt0_data_t hprt0 = {.d32 = 0 };

	root_hub_devnum = 0;
	memset(&g_core_if, 0, sizeof(g_core_if));
	dwc_otg_cil_init(&g_core_if, (uint32_t *)CONFIG_SYS_USB_ADDRESS);

	if ((g_core_if.snpsid & 0xFFFFF000) !=
		0x4F542000) {
		printf("SNPSID is invalid (not DWC OTG device): %08x\n", g_core_if.snpsid);
		return -1;
	}

	dwc_otg_core_init(&g_core_if);
	dwc_otg_core_host_init(&g_core_if);

	hprt0.d32 = dwc_otg_read_hprt0(&g_core_if);
	hprt0.b.prtrst = 1;
	dwc_write_reg32(g_core_if.host_if->hprt0, hprt0.d32);
	mdelay(50);
	hprt0.b.prtrst = 0;
	dwc_write_reg32(g_core_if.host_if->hprt0, hprt0.d32);
	
	for (i = 0; i < MAX_DEVICE; i++) {
		for (j = 0; j < MAX_ENDPOINT; j++) {
			control_data_toggle[i][j] = DWC_OTG_HC_PID_DATA1;
			bulk_data_toggle[i][j] = DWC_OTG_HC_PID_DATA0;
		}
	}

	return 0;
}

int usb_lowlevel_stop(int index)
{
	free(allocated_buffer);

	return 0;
}
Ejemplo n.º 2
0
static int dwc_otg_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
				 void *buffer, int transfer_len,
				 struct devrequest *cmd)
{
	int leni = transfer_len;
	int len = 0;
	int stat = 0;
	__u16 bmRType_bReq;
	__u16 wValue;
	__u16 wLength;
	unsigned char data[32];
	hprt0_data_t hprt0 = {.d32 = 0 };

	if (usb_pipeint(pipe)) {
		printf("Root-Hub submit IRQ: NOT implemented");
		return 0;
	}

	bmRType_bReq  = cmd->requesttype | (cmd->request << 8);
	wValue	      = cpu_to_le16 (cmd->value);
	wLength	      = cpu_to_le16 (cmd->length);

	switch (bmRType_bReq) {
	case RH_GET_STATUS:
		*(__u16 *)buffer = cpu_to_le16(1);
		len = 2;
		break;
	case RH_GET_STATUS | RH_INTERFACE:
		*(__u16 *)buffer = cpu_to_le16(0);
		len = 2;
		break;
	case RH_GET_STATUS | RH_ENDPOINT:
		*(__u16 *)buffer = cpu_to_le16(0);
		len = 2;
		break;
	case RH_GET_STATUS | RH_CLASS:
		*(__u32 *)buffer = cpu_to_le32(0);
		len = 4;
		break;
	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
		{
			uint32_t port_status = 0;
			uint32_t port_change = 0;
			hprt0.d32 = dwc_read_reg32(g_core_if.host_if->hprt0);
			if (hprt0.b.prtconnsts)
				port_status |= USB_PORT_STAT_CONNECTION;
			if (hprt0.b.prtena)
				port_status |= USB_PORT_STAT_ENABLE;
			if (hprt0.b.prtsusp)
				port_status |= USB_PORT_STAT_SUSPEND;
			if (hprt0.b.prtovrcurract)
				port_status |= USB_PORT_STAT_OVERCURRENT;
			if (hprt0.b.prtrst)
				port_status |= USB_PORT_STAT_RESET;
			if (hprt0.b.prtpwr)
				port_status |= USB_PORT_STAT_POWER;

			port_status |= USB_PORT_STAT_HIGH_SPEED;

			if (hprt0.b.prtenchng)
				port_change |= USB_PORT_STAT_C_ENABLE;
			if (hprt0.b.prtconndet)
				port_change |= USB_PORT_STAT_C_CONNECTION;
			if (hprt0.b.prtovrcurrchng)
				port_change |= USB_PORT_STAT_C_OVERCURRENT;

			*(__u32 *)buffer = cpu_to_le32(port_status |
						(port_change << 16));
			len = 4;
		}
		break;
	case RH_CLEAR_FEATURE | RH_ENDPOINT:
	case RH_CLEAR_FEATURE | RH_CLASS:
		break;

	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
		switch (wValue) {
		case RH_C_PORT_CONNECTION:
			hprt0.d32 = dwc_read_reg32(g_core_if.host_if->hprt0);
			hprt0.b.prtconndet = 1;
			dwc_write_reg32(g_core_if.host_if->hprt0, hprt0.d32);
			break;
		}
		break;

	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
		switch (wValue) {
		case (RH_PORT_SUSPEND):
			break;

		case (RH_PORT_RESET):
			hprt0.d32 = dwc_otg_read_hprt0(&g_core_if);
			hprt0.b.prtrst = 1;
			dwc_write_reg32(g_core_if.host_if->hprt0, hprt0.d32);
			mdelay(50);
			hprt0.b.prtrst = 0;
			dwc_write_reg32(g_core_if.host_if->hprt0, hprt0.d32);

			break;

		case (RH_PORT_POWER):
			hprt0.d32 = dwc_otg_read_hprt0(&g_core_if);
			hprt0.b.prtpwr = 1;
			dwc_write_reg32(g_core_if.host_if->hprt0, hprt0.d32);
			break;

		case (RH_PORT_ENABLE):
			break;
		}
		break;
	case RH_SET_ADDRESS:
		root_hub_devnum = wValue;
		break;
	case RH_GET_DESCRIPTOR:
		switch ((wValue & 0xff00) >> 8) {
		case (0x01): /* device descriptor */
			len = min_t(unsigned int,
				  leni,
				  min_t(unsigned int,
				      sizeof(root_hub_dev_des),
				      wLength));
			memcpy(buffer, root_hub_dev_des, len);
			break;
		case (0x02): /* configuration descriptor */
			len = min_t(unsigned int,
				  leni,
				  min_t(unsigned int,
				      sizeof(root_hub_config_des),
				      wLength));
			memcpy(buffer, root_hub_config_des, len);
			break;
		case (0x03): /* string descriptors */
			if (wValue == 0x0300) {
				len = min_t(unsigned int,
					  leni,
					  min_t(unsigned int,
					      sizeof(root_hub_str_index0),
					      wLength));
				memcpy(buffer, root_hub_str_index0, len);
			}
			if (wValue == 0x0301) {
				len = min_t(unsigned int,
					  leni,
					  min_t(unsigned int,
					      sizeof(root_hub_str_index1),
					      wLength));
				memcpy(buffer, root_hub_str_index1, len);
			}
			break;
		default:
			stat = USB_ST_STALLED;
		}
		break;

	case RH_GET_DESCRIPTOR | RH_CLASS:
	{
		__u32 temp = 0x00000001;

		data[0] = 9;		/* min length; */
		data[1] = 0x29;
		data[2] = temp & RH_A_NDP;
		data[3] = 0;
		if (temp & RH_A_PSM)
			data[3] |= 0x1;
		if (temp & RH_A_NOCP)
			data[3] |= 0x10;
		else if (temp & RH_A_OCPM)
			data[3] |= 0x8;

		/* corresponds to data[4-7] */
		data[5] = (temp & RH_A_POTPGT) >> 24;
		data[7] = temp & RH_B_DR;
		if (data[2] < 7) {
			data[8] = 0xff;
		} else {
			data[0] += 2;
			data[8] = (temp & RH_B_DR) >> 8;
			data[10] = data[9] = 0xff;
		}

		len = min_t(unsigned int, leni,
			    min_t(unsigned int, data[0], wLength));
		memcpy(buffer, data, len);
		break;
	}

	case RH_GET_CONFIGURATION:
		*(__u8 *) buffer = 0x01;
		len = 1;
		break;
	case RH_SET_CONFIGURATION:
		break;
	default:
		printf("unsupported root hub command\n");
		stat = USB_ST_STALLED;
	}
Ejemplo n.º 3
0
void w_conn_id_status_change(void *p)
{
	dwc_otg_core_if_t *core_if = p;
	uint32_t count = 0;
	gotgctl_data_t gotgctl = {.d32 = 0 };

	gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
	DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
	DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);

	/* B-Device connector (Device Mode) */
	if (gotgctl.b.conidsts) {
		/* Wait for switch to device mode. */
		while (!dwc_otg_is_device_mode(core_if)) {
			DWC_PRINTF("Waiting for Peripheral Mode, Mode=%s\n",
				   (dwc_otg_is_host_mode(core_if) ? "Host" :
				    "Peripheral"));
			dwc_mdelay(100);
			if (++count > 10000)
				break;
		}
		DWC_ASSERT(++count < 10000,
			   "Connection id status change timed out");
		core_if->op_state = B_PERIPHERAL;
#if defined(CONFIG_BATTERY_NXE2000)
		otgid_power_control_by_dwc(0);
#elif defined(CONFIG_KP_AXP22)
		axp_otg_power_control(0);
#endif
		dwc_otg_set_prtpower(core_if, 0);
		core_if->host_flag = 0;
		dwc_otg_core_init(core_if);
		dwc_otg_enable_global_interrupts(core_if);
		cil_pcd_start(core_if);
	} else {
		/* A-Device connector (Host Mode) */
		while (!dwc_otg_is_host_mode(core_if)) {
			DWC_PRINTF("Waiting for Host Mode, Mode=%s\n",
				   (dwc_otg_is_host_mode(core_if) ? "Host" :
				    "Peripheral"));
			dwc_mdelay(100);
			if (++count > 10000)
				break;
		}
		DWC_ASSERT(++count < 10000,
			   "Connection id status change timed out");
		core_if->op_state = A_HOST;
		/*
		 * Initialize the Core for Host mode.
		 */
		core_if->host_flag = 1;
		dwc_otg_core_init(core_if);
		dwc_otg_enable_global_interrupts(core_if);
		cil_hcd_start(core_if);
	}
}

/**
 * This function handles the Connector ID Status Change Interrupt.  It
 * reads the OTG Interrupt Register (GOTCTL) to determine whether this
 * is a Device to Host Mode transition or a Host Mode to Device
 * Transition. 
 *
 * This only occurs when the cable is connected/removed from the PHY
 * connector.
 *
 * @param core_if Programming view of DWC_otg controller.
 */
int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t * core_if)
{

	/*
	 * Need to disable SOF interrupt immediately. If switching from device
	 * to host, the PCD interrupt handler won't handle the interrupt if
	 * host mode is already set. The HCD interrupt handler won't get
	 * called if the HCD state is HALT. This means that the interrupt does
	 * not get handled and Linux complains loudly.
	 */
	gintmsk_data_t gintmsk = {.d32 = 0 };
	gintsts_data_t gintsts = {.d32 = 0 };

	gintmsk.b.sofintr = 1;
	DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);

	DWC_DEBUGPL(DBG_CIL,
		    " ++Connector ID Status Change Interrupt++  (%s)\n",
		    (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"));
	
	DWC_SPINUNLOCK(core_if->lock);

	/*
	 * Need to schedule a work, as there are possible DELAY function calls
	 * Release lock before scheduling workq as it holds spinlock during scheduling
	 */

	DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change,
			   core_if, "connection id status change");
	DWC_SPINLOCK(core_if->lock);

	/* Set flag and clear interrupt */
	gintsts.b.conidstschng = 1;
	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);

	return 1;
}

/**
 * This interrupt indicates that a device is initiating the Session
 * Request Protocol to request the host to turn on bus power so a new
 * session can begin. The handler responds by turning on bus power. If
 * the DWC_otg controller is in low power mode, the handler brings the
 * controller out of low power mode before turning on bus power.
 *
 * @param core_if Programming view of DWC_otg controller.
 */
int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t * core_if)
{
	gintsts_data_t gintsts;

#ifndef DWC_HOST_ONLY
	DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");

	if (dwc_otg_is_device_mode(core_if)) {
		DWC_PRINTF("SRP: Device mode\n");
	} else {
		hprt0_data_t hprt0;
		DWC_PRINTF("SRP: Host mode\n");

		/* Turn on the port power bit. */
		hprt0.d32 = dwc_otg_read_hprt0(core_if);
		hprt0.b.prtpwr = 1;
		DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);

		/* Start the Connection timer. So a message can be displayed
		 * if connect does not occur within 10 seconds. */
		cil_hcd_session_start(core_if);
	}
#endif

	/* Clear interrupt */
	gintsts.d32 = 0;
	gintsts.b.sessreqintr = 1;
	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);

	return 1;
}

void w_wakeup_detected(void *p)
{
	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) p;
	/*
	 * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
	 * so that OPT tests pass with all PHYs).
	 */
	hprt0_data_t hprt0 = {.d32 = 0 };
#if 0
	pcgcctl_data_t pcgcctl = {.d32 = 0 };
	/* Restart the Phy Clock */
	pcgcctl.b.stoppclk = 1;
	DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
	dwc_udelay(10);
#endif //0
	hprt0.d32 = dwc_otg_read_hprt0(core_if);
	DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
//      dwc_mdelay(70);
	hprt0.b.prtres = 0;	/* Resume */
	DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
	DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n",
		    DWC_READ_REG32(core_if->host_if->hprt0));

	cil_hcd_resume(core_if);

	/** Change to L0 state*/
	core_if->lx_state = DWC_OTG_L0;
}

/**
 * This interrupt indicates that the DWC_otg controller has detected a
 * resume or remote wakeup sequence. If the DWC_otg controller is in
 * low power mode, the handler must brings the controller out of low
 * power mode. The controller automatically begins resume
 * signaling. The handler schedules a time to stop resume signaling.
 */
int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t * core_if)
{
	gintsts_data_t gintsts;

	DWC_DEBUGPL(DBG_ANY,
		    "++Resume and Remote Wakeup Detected Interrupt++\n");

	DWC_PRINTF("%s lxstate = %d\n", __func__, core_if->lx_state);

	if (dwc_otg_is_device_mode(core_if)) {
		dctl_data_t dctl = {.d32 = 0 };
		DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n",
			    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
					   dsts));
		if (core_if->lx_state == DWC_OTG_L2) {
#ifdef PARTIAL_POWER_DOWN
			if (core_if->hwcfg4.b.power_optimiz) {
				pcgcctl_data_t power = {.d32 = 0 };

				power.d32 = DWC_READ_REG32(core_if->pcgcctl);
				DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n",
					    power.d32);

				power.b.stoppclk = 0;
				DWC_WRITE_REG32(core_if->pcgcctl, power.d32);

				power.b.pwrclmp = 0;
				DWC_WRITE_REG32(core_if->pcgcctl, power.d32);

				power.b.rstpdwnmodule = 0;
				DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
			}
#endif
			/* Clear the Remote Wakeup Signaling */
			dctl.b.rmtwkupsig = 1;
			DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
					 dctl, dctl.d32, 0);

			DWC_SPINUNLOCK(core_if->lock);
			if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
				core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
			}
			DWC_SPINLOCK(core_if->lock);
		} else {
			glpmcfg_data_t lpmcfg;
			lpmcfg.d32 =
			    DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
			lpmcfg.b.hird_thres &= (~(1 << 4));
			DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
					lpmcfg.d32);
		}
		/** Change to L0 state*/
		core_if->lx_state = DWC_OTG_L0;
	} else {
		if (core_if->lx_state != DWC_OTG_L1) {
			pcgcctl_data_t pcgcctl = {.d32 = 0 };

			/* Restart the Phy Clock */
			pcgcctl.b.stoppclk = 1;
			DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
			DWC_TIMER_SCHEDULE(core_if->wkp_timer, 71);
		} else {
			/** Change to L0 state*/
			core_if->lx_state = DWC_OTG_L0;
		}
	}
void w_conn_id_status_change(void *p)
{
	dwc_otg_core_if_t *core_if = p;
	uint32_t count = 0;
	gotgctl_data_t gotgctl = {.d32 = 0 };

	gotgctl.d32 = dwc_read_reg32(&core_if->core_global_regs->gotgctl);
	DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
	DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);

	/* B-Device connector (Device Mode) */
	if (gotgctl.b.conidsts) {
		/* Wait for switch to device mode. */
		while (!dwc_otg_is_device_mode(core_if)) {
			DWC_PRINTF("Waiting for Peripheral Mode, Mode=%s\n",
				   (dwc_otg_is_host_mode(core_if) ? "Host" :
				    "Peripheral"));
			dwc_mdelay(100);
			if (++count > 10000)
				break;
		}
		DWC_ASSERT(++count < 10000,
			   "Connection id status change timed out");
#ifdef CONFIG_USB_OTG_UTILS
		if (core_if->xceiver->otg->set_vbus)
			core_if->xceiver->otg->set_vbus(core_if->xceiver->otg, false);
#endif
		core_if->op_state = B_PERIPHERAL;
		dwc_otg_core_init(core_if);
		dwc_otg_enable_global_interrupts(core_if);
		cil_pcd_start(core_if);
	} else {
		/* A-Device connector (Host Mode) */
		while (!dwc_otg_is_host_mode(core_if)) {
			DWC_PRINTF("Waiting for Host Mode, Mode=%s\n",
				   (dwc_otg_is_host_mode(core_if) ? "Host" :
				    "Peripheral"));
			dwc_mdelay(100);
			if (++count > 10000)
				break;
		}
		DWC_ASSERT(++count < 10000,
			   "Connection id status change timed out");
		core_if->op_state = A_HOST;
		/*
		 * Initialize the Core for Host mode.
		 */
		dwc_otg_core_init(core_if);
		dwc_otg_enable_global_interrupts(core_if);
		cil_hcd_start(core_if);
	}
}

/**
 * This function handles the Connector ID Status Change Interrupt.  It
 * reads the OTG Interrupt Register (GOTCTL) to determine whether this
 * is a Device to Host Mode transition or a Host Mode to Device
 * Transition.
 *
 * This only occurs when the cable is connected/removed from the PHY
 * connector.
 *
 * @param core_if Programming view of DWC_otg controller.
 */
int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t *core_if)
{

	/*
	 * Need to disable SOF interrupt immediately. If switching from device
	 * to host, the PCD interrupt handler won't handle the interrupt if
	 * host mode is already set. The HCD interrupt handler won't get
	 * called if the HCD state is HALT. This means that the interrupt does
	 * not get handled and Linux complains loudly.
	 */
	gintmsk_data_t gintmsk = {.d32 = 0 };
	gintsts_data_t gintsts = {.d32 = 0 };

	gintmsk.b.sofintr = 1;
	dwc_modify_reg32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);

	DWC_DEBUGPL(DBG_CIL,
		    " ++Connector ID Status Change Interrupt++  (%s)\n",
		    (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"));

	/*
	 * Need to schedule a work, as there are possible DELAY function calls
	 */
	DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change,
			   core_if, "connection id status change");

	/* Set flag and clear interrupt */
	gintsts.b.conidstschng = 1;
	dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);

	return 1;
}

/**
 * This interrupt indicates that a device is initiating the Session
 * Request Protocol to request the host to turn on bus power so a new
 * session can begin. The handler responds by turning on bus power. If
 * the DWC_otg controller is in low power mode, the handler brings the
 * controller out of low power mode before turning on bus power.
 *
 * @param core_if Programming view of DWC_otg controller.
 */
int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t *core_if)
{
	hprt0_data_t hprt0;
	gintsts_data_t gintsts;

#ifndef DWC_HOST_ONLY
	DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");

	if (dwc_otg_is_device_mode(core_if)) {
		DWC_PRINTF("SRP: Device mode\n");
	} else {
		DWC_PRINTF("SRP: Host mode\n");
		/* Turn on the port power bit. */
		hprt0.d32 = dwc_otg_read_hprt0(core_if);
		hprt0.b.prtpwr = 1;
		dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);

#ifdef CONFIG_USB_OTG
		if (core_if->core_params->otg_supp_enable) {
			/* Schedule a work item to init the core */
			DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_init_core,
					   core_if, "SRP detected");
		} else
#endif
		{
			/* Start the Connection timer. So a message can be displayed
			 * if connect does not occur within connection wait timeout */
			cil_hcd_session_start(core_if);
		}
	}
#endif

	/* Clear interrupt */
	gintsts.d32 = 0;
	gintsts.b.sessreqintr = 1;
	dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);

	return 1;
}

void w_wakeup_detected(void *p)
{
	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *)p;
	/*
	 * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
	 * so that OPT tests pass with all PHYs).
	 */
	hprt0_data_t hprt0 = {.d32 = 0 };
#if 0
	pcgcctl_data_t pcgcctl = {.d32 = 0 };
	/* Restart the Phy Clock */
	pcgcctl.b.stoppclk = 1;
	dwc_modify_reg32(core_if->pcgcctl, pcgcctl.d32, 0);
	dwc_udelay(10);
#endif /*0 */
	hprt0.d32 = dwc_otg_read_hprt0(core_if);
	DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
/*      dwc_mdelay(70); */
	hprt0.b.prtres = 0;	/* Resume */
	dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
	DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n",
		    dwc_read_reg32(core_if->host_if->hprt0));

	cil_hcd_resume(core_if);

	/** Change to L0 state*/
	core_if->lx_state = DWC_OTG_L0;
}

void w_a_periph_done(void *p)
{
	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *)p;

	if (core_if->op_state == A_PERIPHERAL) {
		/* Clear the a_peripheral flag, back to a_host. */
		cil_pcd_stop(core_if);
		cil_hcd_start(core_if);
		core_if->op_state = A_HOST;
	}
}

void w_peri_suspend_powersaving(void *p)
{
	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *)p;

	if (core_if) {
		/* Clear DWC Core interrupts before PHY suspend,
		   this is because to prevent DWC core Hangs while 
		   accessing some registers with PHY suspended if at
		   all we get some core interrupts when phy in suspend*/

		/* Clear any pending OTG Interrupts */
		dwc_write_reg32(&core_if->core_global_regs->gotgint, 0xFFFFFFFF);

		/* Clear any pending interrupts */
		dwc_write_reg32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);

		dwc_otg_disable_global_interrupts(core_if);		

		/* Suspend trasceiver */
		usb_phy_set_suspend(core_if->xceiver, 1);
	}
}
Ejemplo n.º 5
0
/**
 * This function handles the Connector ID Status Change Interrupt.  It
 * reads the OTG Interrupt Register (GOTCTL) to determine whether this
 * is a Device to Host Mode transition or a Host Mode to Device
 * Transition.  
 *
 * This only occurs when the cable is connected/removed from the PHY
 * connector.
 *
 * @param _core_if Programming view of DWC_otg controller.
 */ 
int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t *
						      _core_if) 
{
	uint32_t count = 0;
	gintsts_data_t gintsts = {.d32 = 0};
	gintmsk_data_t gintmsk = {.d32 = 0};
	gotgctl_data_t gotgctl = {.d32 = 0};
	
	/*
	 * Need to disable SOF interrupt immediately. If switching from device
	 * to host, the PCD interrupt handler won't handle the interrupt if
	 * host mode is already set. The HCD interrupt handler won't get
	 * called if the HCD state is HALT. This means that the interrupt does
	 * not get handled and Linux complains loudly.
	 */ 
	gintmsk.b.sofintr = 1;
	dwc_modify_reg32(&_core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
	DWC_DEBUGPL(DBG_CIL,
		      " ++Connector ID Status Change Interrupt++  (%s)\n",
		      (dwc_otg_is_host_mode(_core_if) ? "Host" : "Device"));
	gotgctl.d32 = dwc_read_reg32(&_core_if->core_global_regs->gotgctl);
	DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
	DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);
	
	/* B-Device connector (Device Mode) */ 
	if (gotgctl.b.conidsts) {
		
		/* Wait for switch to device mode. */ 
		while (!dwc_otg_is_device_mode(_core_if)) {
			DWC_PRINT("Waiting for Peripheral Mode, Mode=%s\n", 
				   (dwc_otg_is_host_mode(_core_if) ? "Host" :
				    "Peripheral"));
			MDELAY(100);
			if (++count > 10000)
				*(uint32_t *) NULL = 0;
		}
		_core_if->op_state = B_PERIPHERAL;
		dwc_otg_core_init(_core_if);
		dwc_otg_enable_global_interrupts(_core_if);
		pcd_start(_core_if);
	} else {
		
		/* A-Device connector (Host Mode) */ 
		while (!dwc_otg_is_host_mode(_core_if)) {
			DWC_PRINT("Waiting for Host Mode, Mode=%s\n", 
				   (dwc_otg_is_host_mode(_core_if) ? "Host" :
				    "Peripheral"));
			MDELAY(100);
			if (++count > 10000)
				*(uint32_t *) NULL = 0;
		}
		_core_if->op_state = A_HOST;
		
		/*
		 * Initialize the Core for Host mode.
		 */ 
		dwc_otg_core_init(_core_if);
		dwc_otg_enable_global_interrupts(_core_if);
		hcd_start(_core_if);
	}
	
	/* Set flag and clear interrupt */ 
	gintsts.b.conidstschng = 1;
	dwc_write_reg32(&_core_if->core_global_regs->gintsts, gintsts.d32);
	return 1;
}

/** 
 * This interrupt indicates that a device is initiating the Session
 * Request Protocol to request the host to turn on bus power so a new
 * session can begin. The handler responds by turning on bus power. If
 * the DWC_otg controller is in low power mode, the handler brings the
 * controller out of low power mode before turning on bus power. 
 *
 * @param _core_if Programming view of DWC_otg controller.
 */ 
int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t * _core_if) 
{
	gintsts_data_t gintsts;
	
#ifndef DWC_HOST_ONLY
	hprt0_data_t hprt0;
	DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");
	if (dwc_otg_is_device_mode(_core_if)) {
		DWC_PRINT("SRP: Device mode\n");
	} else {
		DWC_PRINT("SRP: Host mode\n");
		
		/* Turn on the port power bit. */ 
		hprt0.d32 = dwc_otg_read_hprt0(_core_if);
		hprt0.b.prtpwr = 1;
		dwc_write_reg32(_core_if->host_if->hprt0, hprt0.d32);
		
		/* Start the Connection timer. So a message can be displayed
		 * if connect does not occur within 10 seconds. */ 
		hcd_session_start(_core_if);
	}
	
#endif	/*  */
	    
	/* Clear interrupt */ 
	gintsts.d32 = 0;
	gintsts.b.sessreqintr = 1;
	dwc_write_reg32(&_core_if->core_global_regs->gintsts, gintsts.d32);
	return 1;
}

/** 
 * This interrupt indicates that the DWC_otg controller has detected a
 * resume or remote wakeup sequence. If the DWC_otg controller is in
 * low power mode, the handler must brings the controller out of low
 * power mode. The controller automatically begins resume
 * signaling. The handler schedules a time to stop resume signaling.
 */ 
int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t * _core_if) 
{
	gintsts_data_t gintsts;
	DWC_DEBUGPL(DBG_ANY,"++Resume and Remote Wakeup Detected Interrupt++\n");
	if (dwc_otg_is_device_mode(_core_if)) {
		dctl_data_t dctl = {.d32 = 0};
		DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n",
				dwc_read_reg32(&_core_if->dev_if->dev_global_regs->dsts));
		
#ifdef PARTIAL_POWER_DOWN
		if (_core_if->hwcfg4.b.power_optimiz) {
			pcgcctl_data_t power = {.d32 = 0};
			power.d32 = dwc_read_reg32(_core_if->pcgcctl);
			DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n", power.d32);
			power.b.stoppclk = 0;
			dwc_write_reg32(_core_if->pcgcctl, power.d32);
			power.b.pwrclmp = 0;
			dwc_write_reg32(_core_if->pcgcctl, power.d32);
			power.b.rstpdwnmodule = 0;
			dwc_write_reg32(_core_if->pcgcctl, power.d32);
		}
		
#endif	/*  */
		/* Clear the Remote Wakeup Signalling */ 
		dctl.b.rmtwkupsig = 1;
		dwc_modify_reg32(&_core_if->dev_if->dev_global_regs->dctl,
				  dctl.d32, 0);
		if (_core_if->pcd_cb && _core_if->pcd_cb->resume_wakeup) {
			_core_if->pcd_cb->resume_wakeup(_core_if->pcd_cb->p);
		}
	} else {
		
		/*
		 * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
		 * so that OPT tests pass with all PHYs).
		 */ 
		hprt0_data_t hprt0 = {.d32 = 0};
		pcgcctl_data_t pcgcctl = {.d32 = 0};
		
		/* Restart the Phy Clock */ 
		pcgcctl.b.stoppclk = 1;
		dwc_modify_reg32(_core_if->pcgcctl, pcgcctl.d32, 0);
		UDELAY(10);
		
		/* Now wait for 70 ms. */ 
		hprt0.d32 = dwc_otg_read_hprt0(_core_if);
		DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
		MDELAY(70);
		hprt0.b.prtres = 0;	/* Resume */
		dwc_write_reg32(_core_if->host_if->hprt0, hprt0.d32);
		DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n",
			     dwc_read_reg32(_core_if->host_if->hprt0));
	}
	
	/* Clear interrupt */ 
	gintsts.d32 = 0;
	gintsts.b.wkupintr = 1;
	dwc_write_reg32(&_core_if->core_global_regs->gintsts, gintsts.d32);
	return 1;
}

/** 
 * This interrupt indicates that a device has been disconnected from
 * the root port. 
 */ 
int32_t dwc_otg_handle_disconnect_intr(dwc_otg_core_if_t * _core_if) 
{
	gintsts_data_t gintsts;
	printk(KERN_ERR "  Disconnect Detected Interrupt++ (%s) %s\n", 
		 (dwc_otg_is_host_mode(_core_if) ? "Host" : "Device"),
		 op_state_str(_core_if));
	DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n",
		     (dwc_otg_is_host_mode(_core_if) ? "Host" : "Device"),
		     op_state_str(_core_if));
	
/** @todo Consolidate this if statement. */ 
#ifndef DWC_HOST_ONLY
	if (_core_if->op_state == B_HOST) {
		
		/* If in device mode Disconnect and stop the HCD, then
		 * start the PCD. */ 
		hcd_disconnect(_core_if);
		pcd_start(_core_if);
		_core_if->op_state = B_PERIPHERAL;
	} else if (dwc_otg_is_device_mode(_core_if)) {
		gotgctl_data_t gotgctl = {.d32 = 0};
		gotgctl.d32 = dwc_read_reg32(&_core_if->core_global_regs->gotgctl);
		if (gotgctl.b.hstsethnpen == 1) {
			/* Do nothing, if HNP in process the OTG
			 * interrupt "Host Negotiation Detected"
			 * interrupt will do the mode switch.
			 */ 
		} else if (gotgctl.b.devhnpen == 0) {
			/* If in device mode Disconnect and stop the HCD, then
			 * start the PCD. */ 
			hcd_disconnect(_core_if);
			pcd_start(_core_if);
			_core_if->op_state = B_PERIPHERAL;
		} else {
			DWC_DEBUGPL(DBG_ANY, "!a_peripheral && !devhnpen\n");
		}
	} else {
		if (_core_if->op_state == A_HOST) {
			/* A-Cable still connected but device disconnected. */ 
			hcd_disconnect(_core_if);
		}
	}
	
#endif	/*  */
	gintsts.d32 = 0;
	gintsts.b.disconnect = 1;
	dwc_write_reg32(&_core_if->core_global_regs->gintsts, gintsts.d32);
	return 1;
}

/**
 * This interrupt indicates that SUSPEND state has been detected on
 * the USB.
 * 
 * For HNP the USB Suspend interrupt signals the change from
 * "a_peripheral" to "a_host".
 *
 * When power management is enabled the core will be put in low power
 * mode.
 */ 
int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t * _core_if) 
{
	dsts_data_t dsts;
	gintsts_data_t gintsts;
	DWC_DEBUGPL(DBG_ANY, "USB SUSPEND\n");
	if (dwc_otg_is_device_mode(_core_if)) {
		
		/* Check the Device status register to determine if the Suspend
		 * state is active. */ 
		dsts.d32 = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->dsts);
		DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32);
		DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d " 
			     "HWCFG4.power Optimize=%d\n", dsts.b.suspsts,
			     _core_if->hwcfg4.b.power_optimiz);
		
#ifdef PARTIAL_POWER_DOWN
/** @todo Add a module parameter for power management. */ 
		if (dsts.b.suspsts && _core_if->hwcfg4.b.power_optimiz) {
			pcgcctl_data_t power = {.d32 = 0};
			DWC_DEBUGPL(DBG_CIL, "suspend\n");
			power.b.pwrclmp = 1;
			dwc_write_reg32(_core_if->pcgcctl, power.d32);
			power.b.rstpdwnmodule = 1;
			dwc_modify_reg32(_core_if->pcgcctl, 0, power.d32);
			power.b.stoppclk = 1;
			dwc_modify_reg32(_core_if->pcgcctl, 0, power.d32);
		} else {
			DWC_DEBUGPL(DBG_ANY, "disconnect?\n");
		}
		
#endif	/*  */
		/* PCD callback for suspend. */ 
		pcd_suspend(_core_if);
	} else {
		if (_core_if->op_state == A_PERIPHERAL) {
Ejemplo n.º 6
0
	dwc_otg_adp_write_reg(core_if, adpctl.d32);

	return 0;
}

/**
 * Called to turn on the VBUS after initial ADP probe in host mode.
 * If port power was already enabled in cil_hcd_start function then
 * only schedule a timer.
 *
 * @param core_if the pointer to core_if structure.
 */
void dwc_otg_adp_turnon_vbus(dwc_otg_core_if_t * core_if)
{
	hprt0_data_t hprt0 = {.d32 = 0 };
	hprt0.d32 = dwc_otg_read_hprt0(core_if);
	DWC_PRINTF("Turn on VBUS for 1.1s, port power is %d\n", hprt0.b.prtpwr);

	if (hprt0.b.prtpwr == 0) {
		hprt0.b.prtpwr = 1;
		//DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
	}
	
	dwc_otg_adp_vbuson_timer_start(core_if);
}

/**
 * Called right after driver is loaded
 * to perform initial actions for ADP
 *
 * @param core_if the pointer to core_if structure.