1506 lines · 34.7 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * core.c - ChipIdea USB IP core family device controller * * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. * Copyright (C) 2020 NXP * * Author: David Lopo *	   Peter Chen <peter.chen@nxp.com> * * Main Features: * - Four transfers are supported, usbtest is passed * - USB Certification for gadget: CH9 and Mass Storage are passed * - Low power mode * - USB wakeup */#include <linux/delay.h>#include <linux/device.h>#include <linux/dma-mapping.h>#include <linux/extcon.h>#include <linux/phy/phy.h>#include <linux/platform_device.h>#include <linux/module.h>#include <linux/idr.h>#include <linux/interrupt.h>#include <linux/io.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/pm_runtime.h>#include <linux/pm_domain.h>#include <linux/pinctrl/consumer.h>#include <linux/usb/ch9.h>#include <linux/usb/gadget.h>#include <linux/usb/otg.h>#include <linux/usb/chipidea.h>#include <linux/usb/of.h>#include <linux/of.h>#include <linux/regulator/consumer.h>#include <linux/usb/ehci_def.h> #include "ci.h"#include "udc.h"#include "bits.h"#include "host.h"#include "otg.h"#include "otg_fsm.h" /* Controller register map */static const u8 ci_regs_nolpm[] = {	[CAP_CAPLENGTH]		= 0x00U,	[CAP_HCCPARAMS]		= 0x08U,	[CAP_DCCPARAMS]		= 0x24U,	[CAP_TESTMODE]		= 0x38U,	[OP_USBCMD]		= 0x00U,	[OP_USBSTS]		= 0x04U,	[OP_USBINTR]		= 0x08U,	[OP_FRINDEX]		= 0x0CU,	[OP_DEVICEADDR]		= 0x14U,	[OP_ENDPTLISTADDR]	= 0x18U,	[OP_TTCTRL]		= 0x1CU,	[OP_BURSTSIZE]		= 0x20U,	[OP_ULPI_VIEWPORT]	= 0x30U,	[OP_PORTSC]		= 0x44U,	[OP_DEVLC]		= 0x84U,	[OP_OTGSC]		= 0x64U,	[OP_USBMODE]		= 0x68U,	[OP_ENDPTSETUPSTAT]	= 0x6CU,	[OP_ENDPTPRIME]		= 0x70U,	[OP_ENDPTFLUSH]		= 0x74U,	[OP_ENDPTSTAT]		= 0x78U,	[OP_ENDPTCOMPLETE]	= 0x7CU,	[OP_ENDPTCTRL]		= 0x80U,}; static const u8 ci_regs_lpm[] = {	[CAP_CAPLENGTH]		= 0x00U,	[CAP_HCCPARAMS]		= 0x08U,	[CAP_DCCPARAMS]		= 0x24U,	[CAP_TESTMODE]		= 0xFCU,	[OP_USBCMD]		= 0x00U,	[OP_USBSTS]		= 0x04U,	[OP_USBINTR]		= 0x08U,	[OP_FRINDEX]		= 0x0CU,	[OP_DEVICEADDR]		= 0x14U,	[OP_ENDPTLISTADDR]	= 0x18U,	[OP_TTCTRL]		= 0x1CU,	[OP_BURSTSIZE]		= 0x20U,	[OP_ULPI_VIEWPORT]	= 0x30U,	[OP_PORTSC]		= 0x44U,	[OP_DEVLC]		= 0x84U,	[OP_OTGSC]		= 0xC4U,	[OP_USBMODE]		= 0xC8U,	[OP_ENDPTSETUPSTAT]	= 0xD8U,	[OP_ENDPTPRIME]		= 0xDCU,	[OP_ENDPTFLUSH]		= 0xE0U,	[OP_ENDPTSTAT]		= 0xE4U,	[OP_ENDPTCOMPLETE]	= 0xE8U,	[OP_ENDPTCTRL]		= 0xECU,}; static void hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm){	int i; 	for (i = 0; i < OP_ENDPTCTRL; i++)		ci->hw_bank.regmap[i] =			(i <= CAP_LAST ? ci->hw_bank.cap : ci->hw_bank.op) +			(is_lpm ? ci_regs_lpm[i] : ci_regs_nolpm[i]); 	for (; i <= OP_LAST; i++)		ci->hw_bank.regmap[i] = ci->hw_bank.op +			4 * (i - OP_ENDPTCTRL) +			(is_lpm			 ? ci_regs_lpm[OP_ENDPTCTRL]			 : ci_regs_nolpm[OP_ENDPTCTRL]); } static enum ci_revision ci_get_revision(struct ci_hdrc *ci){	int ver = hw_read_id_reg(ci, ID_ID, VERSION) >> __ffs(VERSION);	enum ci_revision rev = CI_REVISION_UNKNOWN; 	if (ver == 0x2) {		rev = hw_read_id_reg(ci, ID_ID, REVISION)			>> __ffs(REVISION);		rev += CI_REVISION_20;	} else if (ver == 0x0) {		rev = CI_REVISION_1X;	} 	return rev;} /** * hw_read_intr_enable: returns interrupt enable register * * @ci: the controller * * This function returns register data */u32 hw_read_intr_enable(struct ci_hdrc *ci){	return hw_read(ci, OP_USBINTR, ~0);} /** * hw_read_intr_status: returns interrupt status register * * @ci: the controller * * This function returns register data */u32 hw_read_intr_status(struct ci_hdrc *ci){	return hw_read(ci, OP_USBSTS, ~0);} /** * hw_port_test_set: writes port test mode (execute without interruption) * @ci: the controller * @mode: new value * * This function returns an error code */int hw_port_test_set(struct ci_hdrc *ci, u8 mode){	const u8 TEST_MODE_MAX = 7; 	if (mode > TEST_MODE_MAX)		return -EINVAL; 	hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << __ffs(PORTSC_PTC));	return 0;} /** * hw_port_test_get: reads port test mode value * * @ci: the controller * * This function returns port test mode value */u8 hw_port_test_get(struct ci_hdrc *ci){	return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> __ffs(PORTSC_PTC);} static void hw_wait_phy_stable(void){	/*	 * The phy needs some delay to output the stable status from low	 * power mode. And for OTGSC, the status inputs are debounced	 * using a 1 ms time constant, so, delay 2ms for controller to get	 * the stable status, like vbus and id when the phy leaves low power.	 */	usleep_range(2000, 2500);} /* The PHY enters/leaves low power mode */static void ci_hdrc_enter_lpm_common(struct ci_hdrc *ci, bool enable){	enum ci_hw_regs reg = ci->hw_bank.lpm ? OP_DEVLC : OP_PORTSC;	bool lpm = !!(hw_read(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm))); 	if (enable && !lpm)		hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm),				PORTSC_PHCD(ci->hw_bank.lpm));	else if (!enable && lpm)		hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm),				0);} static void ci_hdrc_enter_lpm(struct ci_hdrc *ci, bool enable){	return ci->platdata->enter_lpm(ci, enable);} static int hw_device_init(struct ci_hdrc *ci, void __iomem *base){	u32 reg; 	/* bank is a module variable */	ci->hw_bank.abs = base; 	ci->hw_bank.cap = ci->hw_bank.abs;	ci->hw_bank.cap += ci->platdata->capoffset;	ci->hw_bank.op = ci->hw_bank.cap + (ioread32(ci->hw_bank.cap) & 0xff); 	hw_alloc_regmap(ci, false);	reg = hw_read(ci, CAP_HCCPARAMS, HCCPARAMS_LEN) >>		__ffs(HCCPARAMS_LEN);	ci->hw_bank.lpm  = reg;	if (reg)		hw_alloc_regmap(ci, !!reg);	ci->hw_bank.size = ci->hw_bank.op - ci->hw_bank.abs;	ci->hw_bank.size += OP_LAST;	ci->hw_bank.size /= sizeof(u32); 	reg = hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DEN) >>		__ffs(DCCPARAMS_DEN);	ci->hw_ep_max = reg * 2;   /* cache hw ENDPT_MAX */ 	if (ci->hw_ep_max > ENDPT_MAX)		return -ENODEV; 	ci_hdrc_enter_lpm(ci, false); 	/* Disable all interrupts bits */	hw_write(ci, OP_USBINTR, 0xffffffff, 0); 	/* Clear all interrupts status bits*/	hw_write(ci, OP_USBSTS, 0xffffffff, 0xffffffff); 	ci->rev = ci_get_revision(ci); 	dev_dbg(ci->dev,		"revision: %d, lpm: %d; cap: %px op: %px\n",		ci->rev, ci->hw_bank.lpm, ci->hw_bank.cap, ci->hw_bank.op); 	/* setup lock mode ? */ 	/* ENDPTSETUPSTAT is '0' by default */ 	/* HCSPARAMS.bf.ppc SHOULD BE zero for device */ 	return 0;} void hw_phymode_configure(struct ci_hdrc *ci){	u32 portsc, lpm, sts = 0; 	switch (ci->platdata->phy_mode) {	case USBPHY_INTERFACE_MODE_UTMI:		portsc = PORTSC_PTS(PTS_UTMI);		lpm = DEVLC_PTS(PTS_UTMI);		break;	case USBPHY_INTERFACE_MODE_UTMIW:		portsc = PORTSC_PTS(PTS_UTMI) | PORTSC_PTW;		lpm = DEVLC_PTS(PTS_UTMI) | DEVLC_PTW;		break;	case USBPHY_INTERFACE_MODE_ULPI:		portsc = PORTSC_PTS(PTS_ULPI);		lpm = DEVLC_PTS(PTS_ULPI);		break;	case USBPHY_INTERFACE_MODE_SERIAL:		portsc = PORTSC_PTS(PTS_SERIAL);		lpm = DEVLC_PTS(PTS_SERIAL);		sts = 1;		break;	case USBPHY_INTERFACE_MODE_HSIC:		portsc = PORTSC_PTS(PTS_HSIC);		lpm = DEVLC_PTS(PTS_HSIC);		break;	default:		return;	} 	if (ci->hw_bank.lpm) {		hw_write(ci, OP_DEVLC, DEVLC_PTS(7) | DEVLC_PTW, lpm);		if (sts)			hw_write(ci, OP_DEVLC, DEVLC_STS, DEVLC_STS);	} else {		hw_write(ci, OP_PORTSC, PORTSC_PTS(7) | PORTSC_PTW, portsc);		if (sts)			hw_write(ci, OP_PORTSC, PORTSC_STS, PORTSC_STS);	}}EXPORT_SYMBOL_GPL(hw_phymode_configure); /** * _ci_usb_phy_init: initialize phy taking in account both phy and usb_phy * interfaces * @ci: the controller * * This function returns an error code if the phy failed to init */static int _ci_usb_phy_init(struct ci_hdrc *ci){	int ret; 	if (ci->phy) {		ret = phy_init(ci->phy);		if (ret)			return ret; 		ret = phy_power_on(ci->phy);		if (ret) {			phy_exit(ci->phy);			return ret;		}	} else {		ret = usb_phy_init(ci->usb_phy);	} 	return ret;} /** * ci_usb_phy_exit: deinitialize phy taking in account both phy and usb_phy * interfaces * @ci: the controller */static void ci_usb_phy_exit(struct ci_hdrc *ci){	if (ci->platdata->flags & CI_HDRC_OVERRIDE_PHY_CONTROL)		return; 	if (ci->phy) {		phy_power_off(ci->phy);		phy_exit(ci->phy);	} else {		usb_phy_shutdown(ci->usb_phy);	}} /** * ci_usb_phy_init: initialize phy according to different phy type * @ci: the controller * * This function returns an error code if usb_phy_init has failed */static int ci_usb_phy_init(struct ci_hdrc *ci){	int ret; 	if (ci->platdata->flags & CI_HDRC_OVERRIDE_PHY_CONTROL)		return 0; 	switch (ci->platdata->phy_mode) {	case USBPHY_INTERFACE_MODE_UTMI:	case USBPHY_INTERFACE_MODE_UTMIW:	case USBPHY_INTERFACE_MODE_HSIC:		ret = _ci_usb_phy_init(ci);		if (!ret)			hw_wait_phy_stable();		else			return ret;		hw_phymode_configure(ci);		break;	case USBPHY_INTERFACE_MODE_ULPI:	case USBPHY_INTERFACE_MODE_SERIAL:		hw_phymode_configure(ci);		ret = _ci_usb_phy_init(ci);		if (ret)			return ret;		break;	default:		ret = _ci_usb_phy_init(ci);		if (!ret)			hw_wait_phy_stable();	} 	return ret;}  /** * ci_platform_configure: do controller configure * @ci: the controller * */void ci_platform_configure(struct ci_hdrc *ci){	bool is_device_mode, is_host_mode; 	is_device_mode = hw_read(ci, OP_USBMODE, USBMODE_CM) == USBMODE_CM_DC;	is_host_mode = hw_read(ci, OP_USBMODE, USBMODE_CM) == USBMODE_CM_HC; 	if (is_device_mode) {		phy_set_mode(ci->phy, PHY_MODE_USB_DEVICE); 		if (ci->platdata->flags & CI_HDRC_DISABLE_DEVICE_STREAMING)			hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS,				 USBMODE_CI_SDIS);	} 	if (is_host_mode) {		phy_set_mode(ci->phy, PHY_MODE_USB_HOST); 		if (ci->platdata->flags & CI_HDRC_DISABLE_HOST_STREAMING)			hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS,				 USBMODE_CI_SDIS);	} 	if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED) {		if (ci->hw_bank.lpm)			hw_write(ci, OP_DEVLC, DEVLC_PFSC, DEVLC_PFSC);		else			hw_write(ci, OP_PORTSC, PORTSC_PFSC, PORTSC_PFSC);	} 	if (ci->platdata->flags & CI_HDRC_SET_NON_ZERO_TTHA)		hw_write(ci, OP_TTCTRL, TTCTRL_TTHA_MASK, TTCTRL_TTHA); 	hw_write(ci, OP_USBCMD, 0xff0000, ci->platdata->itc_setting << 16); 	if (ci->platdata->flags & CI_HDRC_OVERRIDE_AHB_BURST)		hw_write_id_reg(ci, ID_SBUSCFG, AHBBRST_MASK,			ci->platdata->ahb_burst_config); 	/* override burst size, take effect only when ahb_burst_config is 0 */	if (!hw_read_id_reg(ci, ID_SBUSCFG, AHBBRST_MASK)) {		if (ci->platdata->flags & CI_HDRC_OVERRIDE_TX_BURST)			hw_write(ci, OP_BURSTSIZE, TX_BURST_MASK,			ci->platdata->tx_burst_size << __ffs(TX_BURST_MASK)); 		if (ci->platdata->flags & CI_HDRC_OVERRIDE_RX_BURST)			hw_write(ci, OP_BURSTSIZE, RX_BURST_MASK,				ci->platdata->rx_burst_size);	}} /** * hw_controller_reset: do controller reset * @ci: the controller  * * This function returns an error code */static int hw_controller_reset(struct ci_hdrc *ci){	int count = 0; 	hw_write(ci, OP_USBCMD, USBCMD_RST, USBCMD_RST);	while (hw_read(ci, OP_USBCMD, USBCMD_RST)) {		udelay(10);		if (count++ > 1000)			return -ETIMEDOUT;	} 	return 0;} /** * hw_device_reset: resets chip (execute without interruption) * @ci: the controller * * This function returns an error code */int hw_device_reset(struct ci_hdrc *ci){	int ret; 	/* should flush & stop before reset */	hw_write(ci, OP_ENDPTFLUSH, ~0, ~0);	hw_write(ci, OP_USBCMD, USBCMD_RS, 0); 	ret = hw_controller_reset(ci);	if (ret) {		dev_err(ci->dev, "error resetting controller, ret=%d\n", ret);		return ret;	} 	if (ci->platdata->notify_event) {		ret = ci->platdata->notify_event(ci,			CI_HDRC_CONTROLLER_RESET_EVENT);		if (ret)			return ret;	}

Lines 1–500 of 1506.