cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

core.c (12463B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Cadence USBSS and USBSSP DRD Driver.
      4 *
      5 * Copyright (C) 2018-2019 Cadence.
      6 * Copyright (C) 2017-2018 NXP
      7 * Copyright (C) 2019 Texas Instruments
      8 *
      9 * Author: Peter Chen <peter.chen@nxp.com>
     10 *         Pawel Laszczak <pawell@cadence.com>
     11 *         Roger Quadros <rogerq@ti.com>
     12 */
     13
     14#include <linux/dma-mapping.h>
     15#include <linux/module.h>
     16#include <linux/kernel.h>
     17#include <linux/platform_device.h>
     18#include <linux/interrupt.h>
     19#include <linux/io.h>
     20#include <linux/pm_runtime.h>
     21
     22#include "core.h"
     23#include "host-export.h"
     24#include "drd.h"
     25
     26static int cdns_idle_init(struct cdns *cdns);
     27
     28static int cdns_role_start(struct cdns *cdns, enum usb_role role)
     29{
     30	int ret;
     31
     32	if (WARN_ON(role > USB_ROLE_DEVICE))
     33		return 0;
     34
     35	mutex_lock(&cdns->mutex);
     36	cdns->role = role;
     37	mutex_unlock(&cdns->mutex);
     38
     39	if (!cdns->roles[role])
     40		return -ENXIO;
     41
     42	if (cdns->roles[role]->state == CDNS_ROLE_STATE_ACTIVE)
     43		return 0;
     44
     45	mutex_lock(&cdns->mutex);
     46	ret = cdns->roles[role]->start(cdns);
     47	if (!ret)
     48		cdns->roles[role]->state = CDNS_ROLE_STATE_ACTIVE;
     49	mutex_unlock(&cdns->mutex);
     50
     51	return ret;
     52}
     53
     54static void cdns_role_stop(struct cdns *cdns)
     55{
     56	enum usb_role role = cdns->role;
     57
     58	if (WARN_ON(role > USB_ROLE_DEVICE))
     59		return;
     60
     61	if (cdns->roles[role]->state == CDNS_ROLE_STATE_INACTIVE)
     62		return;
     63
     64	mutex_lock(&cdns->mutex);
     65	cdns->roles[role]->stop(cdns);
     66	cdns->roles[role]->state = CDNS_ROLE_STATE_INACTIVE;
     67	mutex_unlock(&cdns->mutex);
     68}
     69
     70static void cdns_exit_roles(struct cdns *cdns)
     71{
     72	cdns_role_stop(cdns);
     73	cdns_drd_exit(cdns);
     74}
     75
     76/**
     77 * cdns_core_init_role - initialize role of operation
     78 * @cdns: Pointer to cdns structure
     79 *
     80 * Returns 0 on success otherwise negative errno
     81 */
     82static int cdns_core_init_role(struct cdns *cdns)
     83{
     84	struct device *dev = cdns->dev;
     85	enum usb_dr_mode best_dr_mode;
     86	enum usb_dr_mode dr_mode;
     87	int ret;
     88
     89	dr_mode = usb_get_dr_mode(dev);
     90	cdns->role = USB_ROLE_NONE;
     91
     92	/*
     93	 * If driver can't read mode by means of usb_get_dr_mode function then
     94	 * chooses mode according with Kernel configuration. This setting
     95	 * can be restricted later depending on strap pin configuration.
     96	 */
     97	if (dr_mode == USB_DR_MODE_UNKNOWN) {
     98		if (cdns->version == CDNSP_CONTROLLER_V2) {
     99			if (IS_ENABLED(CONFIG_USB_CDNSP_HOST) &&
    100			    IS_ENABLED(CONFIG_USB_CDNSP_GADGET))
    101				dr_mode = USB_DR_MODE_OTG;
    102			else if (IS_ENABLED(CONFIG_USB_CDNSP_HOST))
    103				dr_mode = USB_DR_MODE_HOST;
    104			else if (IS_ENABLED(CONFIG_USB_CDNSP_GADGET))
    105				dr_mode = USB_DR_MODE_PERIPHERAL;
    106		} else {
    107			if (IS_ENABLED(CONFIG_USB_CDNS3_HOST) &&
    108			    IS_ENABLED(CONFIG_USB_CDNS3_GADGET))
    109				dr_mode = USB_DR_MODE_OTG;
    110			else if (IS_ENABLED(CONFIG_USB_CDNS3_HOST))
    111				dr_mode = USB_DR_MODE_HOST;
    112			else if (IS_ENABLED(CONFIG_USB_CDNS3_GADGET))
    113				dr_mode = USB_DR_MODE_PERIPHERAL;
    114		}
    115	}
    116
    117	/*
    118	 * At this point cdns->dr_mode contains strap configuration.
    119	 * Driver try update this setting considering kernel configuration
    120	 */
    121	best_dr_mode = cdns->dr_mode;
    122
    123	ret = cdns_idle_init(cdns);
    124	if (ret)
    125		return ret;
    126
    127	if (dr_mode == USB_DR_MODE_OTG) {
    128		best_dr_mode = cdns->dr_mode;
    129	} else if (cdns->dr_mode == USB_DR_MODE_OTG) {
    130		best_dr_mode = dr_mode;
    131	} else if (cdns->dr_mode != dr_mode) {
    132		dev_err(dev, "Incorrect DRD configuration\n");
    133		return -EINVAL;
    134	}
    135
    136	dr_mode = best_dr_mode;
    137
    138	if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) {
    139		if ((cdns->version == CDNSP_CONTROLLER_V2 &&
    140		     IS_ENABLED(CONFIG_USB_CDNSP_HOST)) ||
    141		    (cdns->version < CDNSP_CONTROLLER_V2 &&
    142		     IS_ENABLED(CONFIG_USB_CDNS3_HOST)))
    143			ret = cdns_host_init(cdns);
    144		else
    145			ret = -ENXIO;
    146
    147		if (ret) {
    148			dev_err(dev, "Host initialization failed with %d\n",
    149				ret);
    150			goto err;
    151		}
    152	}
    153
    154	if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) {
    155		if (cdns->gadget_init)
    156			ret = cdns->gadget_init(cdns);
    157		else
    158			ret = -ENXIO;
    159
    160		if (ret) {
    161			dev_err(dev, "Device initialization failed with %d\n",
    162				ret);
    163			goto err;
    164		}
    165	}
    166
    167	cdns->dr_mode = dr_mode;
    168
    169	ret = cdns_drd_update_mode(cdns);
    170	if (ret)
    171		goto err;
    172
    173	/* Initialize idle role to start with */
    174	ret = cdns_role_start(cdns, USB_ROLE_NONE);
    175	if (ret)
    176		goto err;
    177
    178	switch (cdns->dr_mode) {
    179	case USB_DR_MODE_OTG:
    180		ret = cdns_hw_role_switch(cdns);
    181		if (ret)
    182			goto err;
    183		break;
    184	case USB_DR_MODE_PERIPHERAL:
    185		ret = cdns_role_start(cdns, USB_ROLE_DEVICE);
    186		if (ret)
    187			goto err;
    188		break;
    189	case USB_DR_MODE_HOST:
    190		ret = cdns_role_start(cdns, USB_ROLE_HOST);
    191		if (ret)
    192			goto err;
    193		break;
    194	default:
    195		ret = -EINVAL;
    196		goto err;
    197	}
    198
    199	return 0;
    200err:
    201	cdns_exit_roles(cdns);
    202	return ret;
    203}
    204
    205/**
    206 * cdns_hw_role_state_machine  - role switch state machine based on hw events.
    207 * @cdns: Pointer to controller structure.
    208 *
    209 * Returns next role to be entered based on hw events.
    210 */
    211static enum usb_role cdns_hw_role_state_machine(struct cdns *cdns)
    212{
    213	enum usb_role role = USB_ROLE_NONE;
    214	int id, vbus;
    215
    216	if (cdns->dr_mode != USB_DR_MODE_OTG) {
    217		if (cdns_is_host(cdns))
    218			role = USB_ROLE_HOST;
    219		if (cdns_is_device(cdns))
    220			role = USB_ROLE_DEVICE;
    221
    222		return role;
    223	}
    224
    225	id = cdns_get_id(cdns);
    226	vbus = cdns_get_vbus(cdns);
    227
    228	/*
    229	 * Role change state machine
    230	 * Inputs: ID, VBUS
    231	 * Previous state: cdns->role
    232	 * Next state: role
    233	 */
    234	role = cdns->role;
    235
    236	switch (role) {
    237	case USB_ROLE_NONE:
    238		/*
    239		 * Driver treats USB_ROLE_NONE synonymous to IDLE state from
    240		 * controller specification.
    241		 */
    242		if (!id)
    243			role = USB_ROLE_HOST;
    244		else if (vbus)
    245			role = USB_ROLE_DEVICE;
    246		break;
    247	case USB_ROLE_HOST: /* from HOST, we can only change to NONE */
    248		if (id)
    249			role = USB_ROLE_NONE;
    250		break;
    251	case USB_ROLE_DEVICE: /* from GADGET, we can only change to NONE*/
    252		if (!vbus)
    253			role = USB_ROLE_NONE;
    254		break;
    255	}
    256
    257	dev_dbg(cdns->dev, "role %d -> %d\n", cdns->role, role);
    258
    259	return role;
    260}
    261
    262static int cdns_idle_role_start(struct cdns *cdns)
    263{
    264	return 0;
    265}
    266
    267static void cdns_idle_role_stop(struct cdns *cdns)
    268{
    269	/* Program Lane swap and bring PHY out of RESET */
    270	phy_reset(cdns->usb3_phy);
    271}
    272
    273static int cdns_idle_init(struct cdns *cdns)
    274{
    275	struct cdns_role_driver *rdrv;
    276
    277	rdrv = devm_kzalloc(cdns->dev, sizeof(*rdrv), GFP_KERNEL);
    278	if (!rdrv)
    279		return -ENOMEM;
    280
    281	rdrv->start = cdns_idle_role_start;
    282	rdrv->stop = cdns_idle_role_stop;
    283	rdrv->state = CDNS_ROLE_STATE_INACTIVE;
    284	rdrv->suspend = NULL;
    285	rdrv->resume = NULL;
    286	rdrv->name = "idle";
    287
    288	cdns->roles[USB_ROLE_NONE] = rdrv;
    289
    290	return 0;
    291}
    292
    293/**
    294 * cdns_hw_role_switch - switch roles based on HW state
    295 * @cdns: controller
    296 */
    297int cdns_hw_role_switch(struct cdns *cdns)
    298{
    299	enum usb_role real_role, current_role;
    300	int ret = 0;
    301
    302	/* Depends on role switch class */
    303	if (cdns->role_sw)
    304		return 0;
    305
    306	pm_runtime_get_sync(cdns->dev);
    307
    308	current_role = cdns->role;
    309	real_role = cdns_hw_role_state_machine(cdns);
    310
    311	/* Do nothing if nothing changed */
    312	if (current_role == real_role)
    313		goto exit;
    314
    315	cdns_role_stop(cdns);
    316
    317	dev_dbg(cdns->dev, "Switching role %d -> %d", current_role, real_role);
    318
    319	ret = cdns_role_start(cdns, real_role);
    320	if (ret) {
    321		/* Back to current role */
    322		dev_err(cdns->dev, "set %d has failed, back to %d\n",
    323			real_role, current_role);
    324		ret = cdns_role_start(cdns, current_role);
    325		if (ret)
    326			dev_err(cdns->dev, "back to %d failed too\n",
    327				current_role);
    328	}
    329exit:
    330	pm_runtime_put_sync(cdns->dev);
    331	return ret;
    332}
    333
    334/**
    335 * cdns_role_get - get current role of controller.
    336 *
    337 * @sw: pointer to USB role switch structure
    338 *
    339 * Returns role
    340 */
    341static enum usb_role cdns_role_get(struct usb_role_switch *sw)
    342{
    343	struct cdns *cdns = usb_role_switch_get_drvdata(sw);
    344
    345	return cdns->role;
    346}
    347
    348/**
    349 * cdns_role_set - set current role of controller.
    350 *
    351 * @sw: pointer to USB role switch structure
    352 * @role: the previous role
    353 * Handles below events:
    354 * - Role switch for dual-role devices
    355 * - USB_ROLE_GADGET <--> USB_ROLE_NONE for peripheral-only devices
    356 */
    357static int cdns_role_set(struct usb_role_switch *sw, enum usb_role role)
    358{
    359	struct cdns *cdns = usb_role_switch_get_drvdata(sw);
    360	int ret = 0;
    361
    362	pm_runtime_get_sync(cdns->dev);
    363
    364	if (cdns->role == role)
    365		goto pm_put;
    366
    367	if (cdns->dr_mode == USB_DR_MODE_HOST) {
    368		switch (role) {
    369		case USB_ROLE_NONE:
    370		case USB_ROLE_HOST:
    371			break;
    372		default:
    373			goto pm_put;
    374		}
    375	}
    376
    377	if (cdns->dr_mode == USB_DR_MODE_PERIPHERAL) {
    378		switch (role) {
    379		case USB_ROLE_NONE:
    380		case USB_ROLE_DEVICE:
    381			break;
    382		default:
    383			goto pm_put;
    384		}
    385	}
    386
    387	cdns_role_stop(cdns);
    388	ret = cdns_role_start(cdns, role);
    389	if (ret)
    390		dev_err(cdns->dev, "set role %d has failed\n", role);
    391
    392pm_put:
    393	pm_runtime_put_sync(cdns->dev);
    394	return ret;
    395}
    396
    397
    398/**
    399 * cdns_wakeup_irq - interrupt handler for wakeup events
    400 * @irq: irq number for cdns3/cdnsp core device
    401 * @data: structure of cdns
    402 *
    403 * Returns IRQ_HANDLED or IRQ_NONE
    404 */
    405static irqreturn_t cdns_wakeup_irq(int irq, void *data)
    406{
    407	struct cdns *cdns = data;
    408
    409	if (cdns->in_lpm) {
    410		disable_irq_nosync(irq);
    411		cdns->wakeup_pending = true;
    412		if ((cdns->role == USB_ROLE_HOST) && cdns->host_dev)
    413			pm_request_resume(&cdns->host_dev->dev);
    414
    415		return IRQ_HANDLED;
    416	}
    417
    418	return IRQ_NONE;
    419}
    420
    421/**
    422 * cdns_init - probe for cdns3/cdnsp core device
    423 * @cdns: Pointer to cdns structure.
    424 *
    425 * Returns 0 on success otherwise negative errno
    426 */
    427int cdns_init(struct cdns *cdns)
    428{
    429	struct device *dev = cdns->dev;
    430	int ret;
    431
    432	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
    433	if (ret) {
    434		dev_err(dev, "error setting dma mask: %d\n", ret);
    435		return ret;
    436	}
    437
    438	mutex_init(&cdns->mutex);
    439
    440	if (device_property_read_bool(dev, "usb-role-switch")) {
    441		struct usb_role_switch_desc sw_desc = { };
    442
    443		sw_desc.set = cdns_role_set;
    444		sw_desc.get = cdns_role_get;
    445		sw_desc.allow_userspace_control = true;
    446		sw_desc.driver_data = cdns;
    447		sw_desc.fwnode = dev->fwnode;
    448
    449		cdns->role_sw = usb_role_switch_register(dev, &sw_desc);
    450		if (IS_ERR(cdns->role_sw)) {
    451			dev_warn(dev, "Unable to register Role Switch\n");
    452			return PTR_ERR(cdns->role_sw);
    453		}
    454	}
    455
    456	if (cdns->wakeup_irq) {
    457		ret = devm_request_irq(cdns->dev, cdns->wakeup_irq,
    458						cdns_wakeup_irq,
    459						IRQF_SHARED,
    460						dev_name(cdns->dev), cdns);
    461
    462		if (ret) {
    463			dev_err(cdns->dev, "couldn't register wakeup irq handler\n");
    464			goto role_switch_unregister;
    465		}
    466	}
    467
    468	ret = cdns_drd_init(cdns);
    469	if (ret)
    470		goto init_failed;
    471
    472	ret = cdns_core_init_role(cdns);
    473	if (ret)
    474		goto init_failed;
    475
    476	spin_lock_init(&cdns->lock);
    477
    478	dev_dbg(dev, "Cadence USB3 core: probe succeed\n");
    479
    480	return 0;
    481init_failed:
    482	cdns_drd_exit(cdns);
    483role_switch_unregister:
    484	if (cdns->role_sw)
    485		usb_role_switch_unregister(cdns->role_sw);
    486
    487	return ret;
    488}
    489EXPORT_SYMBOL_GPL(cdns_init);
    490
    491/**
    492 * cdns_remove - unbind drd driver and clean up
    493 * @cdns: Pointer to cdns structure.
    494 *
    495 * Returns 0 on success otherwise negative errno
    496 */
    497int cdns_remove(struct cdns *cdns)
    498{
    499	cdns_exit_roles(cdns);
    500	usb_role_switch_unregister(cdns->role_sw);
    501
    502	return 0;
    503}
    504EXPORT_SYMBOL_GPL(cdns_remove);
    505
    506#ifdef CONFIG_PM_SLEEP
    507int cdns_suspend(struct cdns *cdns)
    508{
    509	struct device *dev = cdns->dev;
    510	unsigned long flags;
    511
    512	if (pm_runtime_status_suspended(dev))
    513		pm_runtime_resume(dev);
    514
    515	if (cdns->roles[cdns->role]->suspend) {
    516		spin_lock_irqsave(&cdns->lock, flags);
    517		cdns->roles[cdns->role]->suspend(cdns, false);
    518		spin_unlock_irqrestore(&cdns->lock, flags);
    519	}
    520
    521	return 0;
    522}
    523EXPORT_SYMBOL_GPL(cdns_suspend);
    524
    525int cdns_resume(struct cdns *cdns, u8 set_active)
    526{
    527	struct device *dev = cdns->dev;
    528	enum usb_role real_role;
    529	bool role_changed = false;
    530	int ret = 0;
    531
    532	if (cdns_power_is_lost(cdns)) {
    533		if (cdns->role_sw) {
    534			cdns->role = cdns_role_get(cdns->role_sw);
    535		} else {
    536			real_role = cdns_hw_role_state_machine(cdns);
    537			if (real_role != cdns->role) {
    538				ret = cdns_hw_role_switch(cdns);
    539				if (ret)
    540					return ret;
    541				role_changed = true;
    542			}
    543		}
    544
    545		if (!role_changed) {
    546			if (cdns->role == USB_ROLE_HOST)
    547				ret = cdns_drd_host_on(cdns);
    548			else if (cdns->role == USB_ROLE_DEVICE)
    549				ret = cdns_drd_gadget_on(cdns);
    550
    551			if (ret)
    552				return ret;
    553		}
    554	}
    555
    556	if (cdns->roles[cdns->role]->resume)
    557		cdns->roles[cdns->role]->resume(cdns, cdns_power_is_lost(cdns));
    558
    559	if (set_active) {
    560		pm_runtime_disable(dev);
    561		pm_runtime_set_active(dev);
    562		pm_runtime_enable(dev);
    563	}
    564
    565	return 0;
    566}
    567EXPORT_SYMBOL_GPL(cdns_resume);
    568#endif /* CONFIG_PM_SLEEP */
    569
    570MODULE_AUTHOR("Peter Chen <peter.chen@nxp.com>");
    571MODULE_AUTHOR("Pawel Laszczak <pawell@cadence.com>");
    572MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
    573MODULE_DESCRIPTION("Cadence USBSS and USBSSP DRD Driver");
    574MODULE_LICENSE("GPL");