Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1c28026e authored by Manu Gautam's avatar Manu Gautam Committed by Hemant Kumar
Browse files

usb: dwc3-msm: Use dummy buffer as doorbell until GSI is ready



USB GSI wrapper can try to access IPA GSI Doorbell as soon as
endpoint is enabled and transfers are started. However there
is always going to be some delay when transfers are started
and GSI doorbell address is updated. This may result in USB
GSI wrapper accessing address-0. Prevent this by using some
dummy buffer as doorbell until IPA GSI connections are setup.
At that stage driver will override doorbell address with valid
ne.

Change-Id: I477602d33737a994992c5394c6c08d63744e525f
Signed-off-by: default avatarManu Gautam <mgautam@codeaurora.org>
parent 55cb9664
Loading
Loading
Loading
Loading
+71 −53
Original line number Diff line number Diff line
@@ -341,6 +341,8 @@ struct dwc3_msm {
	struct notifier_block	dpdm_nb;
	struct regulator	*dpdm_reg;

	u64			dummy_gsi_db;
	dma_addr_t		dummy_gsi_db_dma;
};

#define USB_HSPHY_3P3_VOL_MIN		3050000 /* uV */
@@ -1002,6 +1004,10 @@ static void gsi_store_ringbase_dbl_info(struct usb_ep *ep,
		ep->name, request->db_reg_phs_addr_lsb,
		(unsigned long long)request->mapped_db_reg_phs_addr_lsb);

	/*
	 * Replace dummy doorbell address with real one as IPA connection
	 * is setup now and GSI must be ready to handle doorbell updates.
	 */
	dwc3_msm_write_reg(mdwc->base,
		GSI_DBL_ADDR_L(mdwc->gsi_reg[DBL_ADDR_L], (n)),
		(u32)request->mapped_db_reg_phs_addr_lsb);
@@ -1263,9 +1269,18 @@ static void gsi_configure_ep(struct usb_ep *ep, struct usb_gsi_request *request)
	struct dwc3_gadget_ep_cmd_params params;
	const struct usb_endpoint_descriptor *desc = ep->desc;
	const struct usb_ss_ep_comp_descriptor *comp_desc = ep->comp_desc;
	int n = ep->ep_intr_num - 1;
	u32 reg;
	int ret;

	/* setup dummy doorbell as IPA connection isn't setup yet */
	dwc3_msm_write_reg_field(mdwc->base,
			GSI_DBL_ADDR_L(mdwc->gsi_reg[DBL_ADDR_L], (n)),
			~0x0, (u32)mdwc->dummy_gsi_db_dma);
	dev_dbg(mdwc->dev, "Dummy DB Addr %pK: %llx %llx (LSB)\n",
		&mdwc->dummy_gsi_db, mdwc->dummy_gsi_db_dma,
		(u32)mdwc->dummy_gsi_db_dma);

	memset(&params, 0x00, sizeof(params));

	/* Configure GSI EP */
@@ -1797,24 +1812,6 @@ static int dwc3_msm_link_clk_reset(struct dwc3_msm *mdwc, bool assert)
	return ret;
}

/* Initialize QSCRATCH registers for HSPHY and SSPHY operation */
static void dwc3_msm_qscratch_reg_init(struct dwc3_msm *mdwc)
{
	if (dwc3_msm_read_reg(mdwc->base, DWC3_GSNPSID) < DWC3_REVISION_250A)
		/* On older cores set XHCI_REV bit to specify revision 1.0 */
		dwc3_msm_write_reg_field(mdwc->base, QSCRATCH_GENERAL_CFG,
					 BIT(2), 1);

	/*
	 * Enable master clock for RAMs to allow BAM to access RAMs when
	 * RAM clock gating is enabled via DWC3's GCTL. Otherwise issues
	 * are seen where RAM clocks get turned OFF in SS mode
	 */
	dwc3_msm_write_reg(mdwc->base, CGCTL_REG,
		dwc3_msm_read_reg(mdwc->base, CGCTL_REG) | 0x18);

}

static void dwc3_msm_vbus_draw_work(struct work_struct *w)
{
	struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
@@ -1824,6 +1821,55 @@ static void dwc3_msm_vbus_draw_work(struct work_struct *w)
	dwc3_msm_gadget_vbus_draw(mdwc, dwc->vbus_draw);
}

static void dwc3_gsi_event_buf_alloc(struct dwc3 *dwc)
{
	struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
	struct dwc3_event_buffer *evt;
	int i;

	if (!mdwc->num_gsi_event_buffers)
		return;

	mdwc->gsi_ev_buff = devm_kzalloc(dwc->dev,
		sizeof(*dwc->ev_buf) * mdwc->num_gsi_event_buffers,
		GFP_KERNEL);
	if (!mdwc->gsi_ev_buff) {
		dev_err(dwc->dev, "can't allocate gsi_ev_buff\n");
		return;
	}

	for (i = 0; i < mdwc->num_gsi_event_buffers; i++) {

		evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL);
		if (!evt)
			return;
		evt->dwc	= dwc;
		evt->length	= DWC3_EVENT_BUFFERS_SIZE;
		evt->buf	= dma_alloc_coherent(dwc->sysdev,
					DWC3_EVENT_BUFFERS_SIZE,
					&evt->dma, GFP_KERNEL);
		if (!evt->buf) {
			dev_err(dwc->dev,
				"can't allocate gsi_evt_buf(%d)\n", i);
			return;
		}
		mdwc->gsi_ev_buff[i] = evt;
	}
	/*
	 * Set-up dummy buffer to use as doorbell while IPA GSI
	 * connection is in progress.
	 */
	mdwc->dummy_gsi_db_dma = dma_map_single(dwc->sysdev,
					&mdwc->dummy_gsi_db,
					sizeof(mdwc->dummy_gsi_db),
					DMA_FROM_DEVICE);

	if (dma_mapping_error(dwc->sysdev, mdwc->dummy_gsi_db_dma)) {
		dev_err(dwc->dev, "failed to map dummy doorbell buffer\n");
		mdwc->dummy_gsi_db_dma = (dma_addr_t)NULL;
	}
}

static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event,
							unsigned int value)
{
@@ -1849,11 +1895,6 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event,
		/* restart USB which performs full reset and reconnect */
		schedule_work(&mdwc->restart_usb_work);
		break;
	case DWC3_CONTROLLER_RESET_EVENT:
		dev_dbg(mdwc->dev, "DWC3_CONTROLLER_RESET_EVENT received\n");
		/* HS & SSPHYs get reset as part of core soft reset */
		dwc3_msm_qscratch_reg_init(mdwc);
		break;
	case DWC3_CONTROLLER_POST_RESET_EVENT:
		dev_dbg(mdwc->dev,
				"DWC3_CONTROLLER_POST_RESET_EVENT received\n");
@@ -1909,7 +1950,6 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event,
			dwc->gadget.is_selfpowered = val.intval;
		else
			dwc->gadget.is_selfpowered = 0;

		break;
	case DWC3_CONTROLLER_NOTIFY_OTG_EVENT:
		dev_dbg(mdwc->dev, "DWC3_CONTROLLER_NOTIFY_OTG_EVENT received\n");
@@ -1928,35 +1968,7 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event,
		break;
	case DWC3_GSI_EVT_BUF_ALLOC:
		dev_dbg(mdwc->dev, "DWC3_GSI_EVT_BUF_ALLOC\n");

		if (!mdwc->num_gsi_event_buffers)
			break;

		mdwc->gsi_ev_buff = devm_kzalloc(dwc->dev,
			sizeof(*dwc->ev_buf) * mdwc->num_gsi_event_buffers,
			GFP_KERNEL);
		if (!mdwc->gsi_ev_buff) {
			dev_err(dwc->dev, "can't allocate gsi_ev_buff\n");
			break;
		}

		for (i = 0; i < mdwc->num_gsi_event_buffers; i++) {

			evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL);
			if (!evt)
				break;
			evt->dwc	= dwc;
			evt->length	= DWC3_EVENT_BUFFERS_SIZE;
			evt->buf	= dma_alloc_coherent(dwc->sysdev,
						DWC3_EVENT_BUFFERS_SIZE,
						&evt->dma, GFP_KERNEL);
			if (!evt->buf) {
				dev_err(dwc->dev,
					"can't allocate gsi_evt_buf(%d)\n", i);
				break;
			}
			mdwc->gsi_ev_buff[i] = evt;
		}
		dwc3_gsi_event_buf_alloc(dwc);
		break;
	case DWC3_GSI_EVT_BUF_SETUP:
		dev_dbg(mdwc->dev, "DWC3_GSI_EVT_BUF_SETUP\n");
@@ -2021,6 +2033,12 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event,
				dma_free_coherent(dwc->sysdev, evt->length,
							evt->buf, evt->dma);
		}
		if (mdwc->dummy_gsi_db_dma) {
			dma_unmap_single(dwc->sysdev, mdwc->dummy_gsi_db_dma,
					 sizeof(mdwc->dummy_gsi_db),
					 DMA_FROM_DEVICE);
			mdwc->dummy_gsi_db_dma = (dma_addr_t)NULL;
		}
		break;
	case DWC3_GSI_EVT_BUF_CLEAR:
		dev_dbg(mdwc->dev, "DWC3_GSI_EVT_BUF_CLEAR\n");