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

omap2430.c (14015B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2005-2007 by Texas Instruments
      4 * Some code has been taken from tusb6010.c
      5 * Copyrights for that are attributable to:
      6 * Copyright (C) 2006 Nokia Corporation
      7 * Tony Lindgren <tony@atomide.com>
      8 *
      9 * This file is part of the Inventra Controller Driver for Linux.
     10 */
     11#include <linux/module.h>
     12#include <linux/kernel.h>
     13#include <linux/sched.h>
     14#include <linux/init.h>
     15#include <linux/list.h>
     16#include <linux/io.h>
     17#include <linux/of.h>
     18#include <linux/platform_device.h>
     19#include <linux/dma-mapping.h>
     20#include <linux/pm_runtime.h>
     21#include <linux/err.h>
     22#include <linux/delay.h>
     23#include <linux/usb/musb.h>
     24#include <linux/phy/omap_control_phy.h>
     25#include <linux/of_platform.h>
     26
     27#include "musb_core.h"
     28#include "omap2430.h"
     29
     30struct omap2430_glue {
     31	struct device		*dev;
     32	struct platform_device	*musb;
     33	enum musb_vbus_id_status status;
     34	struct work_struct	omap_musb_mailbox_work;
     35	struct device		*control_otghs;
     36	unsigned int		is_runtime_suspended:1;
     37	unsigned int		needs_resume:1;
     38	unsigned int		phy_suspended:1;
     39};
     40#define glue_to_musb(g)		platform_get_drvdata(g->musb)
     41
     42static struct omap2430_glue	*_glue;
     43
     44static inline void omap2430_low_level_exit(struct musb *musb)
     45{
     46	u32 l;
     47
     48	/* in any role */
     49	l = musb_readl(musb->mregs, OTG_FORCESTDBY);
     50	l |= ENABLEFORCE;	/* enable MSTANDBY */
     51	musb_writel(musb->mregs, OTG_FORCESTDBY, l);
     52}
     53
     54static inline void omap2430_low_level_init(struct musb *musb)
     55{
     56	u32 l;
     57
     58	l = musb_readl(musb->mregs, OTG_FORCESTDBY);
     59	l &= ~ENABLEFORCE;	/* disable MSTANDBY */
     60	musb_writel(musb->mregs, OTG_FORCESTDBY, l);
     61}
     62
     63static int omap2430_musb_mailbox(enum musb_vbus_id_status status)
     64{
     65	struct omap2430_glue	*glue = _glue;
     66
     67	if (!glue) {
     68		pr_err("%s: musb core is not yet initialized\n", __func__);
     69		return -EPROBE_DEFER;
     70	}
     71	glue->status = status;
     72
     73	if (!glue_to_musb(glue)) {
     74		pr_err("%s: musb core is not yet ready\n", __func__);
     75		return -EPROBE_DEFER;
     76	}
     77
     78	schedule_work(&glue->omap_musb_mailbox_work);
     79
     80	return 0;
     81}
     82
     83/*
     84 * HDRC controls CPEN, but beware current surges during device connect.
     85 * They can trigger transient overcurrent conditions that must be ignored.
     86 *
     87 * Note that we're skipping A_WAIT_VFALL -> A_IDLE and jumping right to B_IDLE
     88 * as set by musb_set_peripheral().
     89 */
     90static void omap_musb_set_mailbox(struct omap2430_glue *glue)
     91{
     92	struct musb *musb = glue_to_musb(glue);
     93	int error;
     94
     95	pm_runtime_get_sync(musb->controller);
     96
     97	dev_dbg(musb->controller, "VBUS %s, devctl %02x\n",
     98		usb_otg_state_string(musb->xceiv->otg->state),
     99		musb_readb(musb->mregs, MUSB_DEVCTL));
    100
    101	switch (glue->status) {
    102	case MUSB_ID_GROUND:
    103		dev_dbg(musb->controller, "ID GND\n");
    104		switch (musb->xceiv->otg->state) {
    105		case OTG_STATE_A_IDLE:
    106			error = musb_set_host(musb);
    107			if (error)
    108				break;
    109			musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
    110			fallthrough;
    111		case OTG_STATE_A_WAIT_VRISE:
    112		case OTG_STATE_A_WAIT_BCON:
    113		case OTG_STATE_A_HOST:
    114			/*
    115			 * On multiple ID ground interrupts just keep enabling
    116			 * VBUS. At least cpcap VBUS shuts down otherwise.
    117			 */
    118			otg_set_vbus(musb->xceiv->otg, 1);
    119			break;
    120		default:
    121			musb->xceiv->otg->state = OTG_STATE_A_IDLE;
    122			musb->xceiv->last_event = USB_EVENT_ID;
    123			if (musb->gadget_driver) {
    124				omap_control_usb_set_mode(glue->control_otghs,
    125							  USB_MODE_HOST);
    126				otg_set_vbus(musb->xceiv->otg, 1);
    127			}
    128			break;
    129		}
    130		break;
    131
    132	case MUSB_VBUS_VALID:
    133		dev_dbg(musb->controller, "VBUS Connect\n");
    134
    135		musb->xceiv->otg->state = OTG_STATE_B_IDLE;
    136		musb->xceiv->last_event = USB_EVENT_VBUS;
    137		omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE);
    138		break;
    139
    140	case MUSB_ID_FLOAT:
    141	case MUSB_VBUS_OFF:
    142		dev_dbg(musb->controller, "VBUS Disconnect\n");
    143
    144		musb->xceiv->last_event = USB_EVENT_NONE;
    145		musb_set_peripheral(musb);
    146		otg_set_vbus(musb->xceiv->otg, 0);
    147		omap_control_usb_set_mode(glue->control_otghs,
    148			USB_MODE_DISCONNECT);
    149		break;
    150	default:
    151		dev_dbg(musb->controller, "ID float\n");
    152	}
    153	pm_runtime_mark_last_busy(musb->controller);
    154	pm_runtime_put_autosuspend(musb->controller);
    155	atomic_notifier_call_chain(&musb->xceiv->notifier,
    156			musb->xceiv->last_event, NULL);
    157}
    158
    159
    160static void omap_musb_mailbox_work(struct work_struct *mailbox_work)
    161{
    162	struct omap2430_glue *glue = container_of(mailbox_work,
    163				struct omap2430_glue, omap_musb_mailbox_work);
    164
    165	omap_musb_set_mailbox(glue);
    166}
    167
    168static irqreturn_t omap2430_musb_interrupt(int irq, void *__hci)
    169{
    170	unsigned long   flags;
    171	irqreturn_t     retval = IRQ_NONE;
    172	struct musb     *musb = __hci;
    173
    174	spin_lock_irqsave(&musb->lock, flags);
    175
    176	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
    177	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
    178	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
    179
    180	if (musb->int_usb || musb->int_tx || musb->int_rx)
    181		retval = musb_interrupt(musb);
    182
    183	spin_unlock_irqrestore(&musb->lock, flags);
    184
    185	return retval;
    186}
    187
    188static int omap2430_musb_init(struct musb *musb)
    189{
    190	u32 l;
    191	int status = 0;
    192	struct device *dev = musb->controller;
    193	struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
    194	struct omap_musb_board_data *data = plat->board_data;
    195
    196	/* We require some kind of external transceiver, hooked
    197	 * up through ULPI.  TWL4030-family PMICs include one,
    198	 * which needs a driver, drivers aren't always needed.
    199	 */
    200	musb->phy = devm_phy_get(dev->parent, "usb2-phy");
    201
    202	/* We can't totally remove musb->xceiv as of now because
    203	 * musb core uses xceiv.state and xceiv.otg. Once we have
    204	 * a separate state machine to handle otg, these can be moved
    205	 * out of xceiv and then we can start using the generic PHY
    206	 * framework
    207	 */
    208	musb->xceiv = devm_usb_get_phy_by_phandle(dev->parent, "usb-phy", 0);
    209
    210	if (IS_ERR(musb->xceiv)) {
    211		status = PTR_ERR(musb->xceiv);
    212
    213		if (status == -ENXIO)
    214			return status;
    215
    216		dev_dbg(dev, "HS USB OTG: no transceiver configured\n");
    217		return -EPROBE_DEFER;
    218	}
    219
    220	if (IS_ERR(musb->phy)) {
    221		dev_err(dev, "HS USB OTG: no PHY configured\n");
    222		return PTR_ERR(musb->phy);
    223	}
    224	musb->isr = omap2430_musb_interrupt;
    225	phy_init(musb->phy);
    226	phy_power_on(musb->phy);
    227
    228	l = musb_readl(musb->mregs, OTG_INTERFSEL);
    229
    230	if (data->interface_type == MUSB_INTERFACE_UTMI) {
    231		/* OMAP4 uses Internal PHY GS70 which uses UTMI interface */
    232		l &= ~ULPI_12PIN;       /* Disable ULPI */
    233		l |= UTMI_8BIT;         /* Enable UTMI  */
    234	} else {
    235		l |= ULPI_12PIN;
    236	}
    237
    238	musb_writel(musb->mregs, OTG_INTERFSEL, l);
    239
    240	dev_dbg(dev, "HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
    241			"sysstatus 0x%x, intrfsel 0x%x, simenable  0x%x\n",
    242			musb_readl(musb->mregs, OTG_REVISION),
    243			musb_readl(musb->mregs, OTG_SYSCONFIG),
    244			musb_readl(musb->mregs, OTG_SYSSTATUS),
    245			musb_readl(musb->mregs, OTG_INTERFSEL),
    246			musb_readl(musb->mregs, OTG_SIMENABLE));
    247
    248	return 0;
    249}
    250
    251static void omap2430_musb_enable(struct musb *musb)
    252{
    253	struct device *dev = musb->controller;
    254	struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
    255
    256	if (glue->status == MUSB_UNKNOWN)
    257		glue->status = MUSB_VBUS_OFF;
    258	omap_musb_set_mailbox(glue);
    259}
    260
    261static void omap2430_musb_disable(struct musb *musb)
    262{
    263	struct device *dev = musb->controller;
    264	struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
    265
    266	if (glue->status != MUSB_UNKNOWN)
    267		omap_control_usb_set_mode(glue->control_otghs,
    268			USB_MODE_DISCONNECT);
    269}
    270
    271static int omap2430_musb_exit(struct musb *musb)
    272{
    273	struct device *dev = musb->controller;
    274	struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
    275
    276	omap2430_low_level_exit(musb);
    277	phy_power_off(musb->phy);
    278	phy_exit(musb->phy);
    279	musb->phy = NULL;
    280	cancel_work_sync(&glue->omap_musb_mailbox_work);
    281
    282	return 0;
    283}
    284
    285static const struct musb_platform_ops omap2430_ops = {
    286	.quirks		= MUSB_DMA_INVENTRA,
    287#ifdef CONFIG_USB_INVENTRA_DMA
    288	.dma_init	= musbhs_dma_controller_create,
    289	.dma_exit	= musbhs_dma_controller_destroy,
    290#endif
    291	.init		= omap2430_musb_init,
    292	.exit		= omap2430_musb_exit,
    293
    294	.enable		= omap2430_musb_enable,
    295	.disable	= omap2430_musb_disable,
    296
    297	.phy_callback	= omap2430_musb_mailbox,
    298};
    299
    300static u64 omap2430_dmamask = DMA_BIT_MASK(32);
    301
    302static int omap2430_probe(struct platform_device *pdev)
    303{
    304	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev);
    305	struct omap_musb_board_data	*data;
    306	struct platform_device		*musb;
    307	struct omap2430_glue		*glue;
    308	struct device_node		*np = pdev->dev.of_node;
    309	struct musb_hdrc_config		*config;
    310	struct device_node		*control_node;
    311	struct platform_device		*control_pdev;
    312	int				ret = -ENOMEM, val;
    313
    314	if (!np)
    315		return -ENODEV;
    316
    317	glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
    318	if (!glue)
    319		goto err0;
    320
    321	musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
    322	if (!musb) {
    323		dev_err(&pdev->dev, "failed to allocate musb device\n");
    324		goto err0;
    325	}
    326
    327	musb->dev.parent		= &pdev->dev;
    328	musb->dev.dma_mask		= &omap2430_dmamask;
    329	musb->dev.coherent_dma_mask	= omap2430_dmamask;
    330
    331	glue->dev			= &pdev->dev;
    332	glue->musb			= musb;
    333	glue->status			= MUSB_UNKNOWN;
    334	glue->control_otghs = ERR_PTR(-ENODEV);
    335
    336	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
    337	if (!pdata)
    338		goto err2;
    339
    340	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
    341	if (!data)
    342		goto err2;
    343
    344	config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
    345	if (!config)
    346		goto err2;
    347
    348	of_property_read_u32(np, "mode", (u32 *)&pdata->mode);
    349	of_property_read_u32(np, "interface-type",
    350			(u32 *)&data->interface_type);
    351	of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps);
    352	of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);
    353	of_property_read_u32(np, "power", (u32 *)&pdata->power);
    354
    355	ret = of_property_read_u32(np, "multipoint", &val);
    356	if (!ret && val)
    357		config->multipoint = true;
    358
    359	pdata->board_data	= data;
    360	pdata->config		= config;
    361
    362	control_node = of_parse_phandle(np, "ctrl-module", 0);
    363	if (control_node) {
    364		control_pdev = of_find_device_by_node(control_node);
    365		of_node_put(control_node);
    366		if (!control_pdev) {
    367			dev_err(&pdev->dev, "Failed to get control device\n");
    368			ret = -EINVAL;
    369			goto err2;
    370		}
    371		glue->control_otghs = &control_pdev->dev;
    372	}
    373
    374	pdata->platform_ops		= &omap2430_ops;
    375
    376	platform_set_drvdata(pdev, glue);
    377
    378	/*
    379	 * REVISIT if we ever have two instances of the wrapper, we will be
    380	 * in big trouble
    381	 */
    382	_glue	= glue;
    383
    384	INIT_WORK(&glue->omap_musb_mailbox_work, omap_musb_mailbox_work);
    385
    386	ret = platform_device_add_resources(musb, pdev->resource, pdev->num_resources);
    387	if (ret) {
    388		dev_err(&pdev->dev, "failed to add resources\n");
    389		goto err2;
    390	}
    391
    392	ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
    393	if (ret) {
    394		dev_err(&pdev->dev, "failed to add platform_data\n");
    395		goto err2;
    396	}
    397
    398	pm_runtime_enable(glue->dev);
    399
    400	ret = platform_device_add(musb);
    401	if (ret) {
    402		dev_err(&pdev->dev, "failed to register musb device\n");
    403		goto err3;
    404	}
    405
    406	return 0;
    407
    408err3:
    409	pm_runtime_disable(glue->dev);
    410
    411err2:
    412	platform_device_put(musb);
    413
    414err0:
    415	return ret;
    416}
    417
    418static int omap2430_remove(struct platform_device *pdev)
    419{
    420	struct omap2430_glue *glue = platform_get_drvdata(pdev);
    421
    422	platform_device_unregister(glue->musb);
    423	pm_runtime_disable(glue->dev);
    424
    425	return 0;
    426}
    427
    428#ifdef CONFIG_PM
    429
    430static int omap2430_runtime_suspend(struct device *dev)
    431{
    432	struct omap2430_glue		*glue = dev_get_drvdata(dev);
    433	struct musb			*musb = glue_to_musb(glue);
    434
    435	if (!musb)
    436		return 0;
    437
    438	musb->context.otg_interfsel = musb_readl(musb->mregs,
    439						 OTG_INTERFSEL);
    440
    441	omap2430_low_level_exit(musb);
    442
    443	if (!glue->phy_suspended) {
    444		phy_power_off(musb->phy);
    445		phy_exit(musb->phy);
    446	}
    447
    448	glue->is_runtime_suspended = 1;
    449
    450	return 0;
    451}
    452
    453static int omap2430_runtime_resume(struct device *dev)
    454{
    455	struct omap2430_glue		*glue = dev_get_drvdata(dev);
    456	struct musb			*musb = glue_to_musb(glue);
    457
    458	if (!musb)
    459		return 0;
    460
    461	if (!glue->phy_suspended) {
    462		phy_init(musb->phy);
    463		phy_power_on(musb->phy);
    464	}
    465
    466	omap2430_low_level_init(musb);
    467	musb_writel(musb->mregs, OTG_INTERFSEL,
    468		    musb->context.otg_interfsel);
    469
    470	/* Wait for musb to get oriented. Otherwise we can get babble */
    471	usleep_range(200000, 250000);
    472
    473	glue->is_runtime_suspended = 0;
    474
    475	return 0;
    476}
    477
    478/* I2C and SPI PHYs need to be suspended before the glue layer */
    479static int omap2430_suspend(struct device *dev)
    480{
    481	struct omap2430_glue *glue = dev_get_drvdata(dev);
    482	struct musb *musb = glue_to_musb(glue);
    483
    484	phy_power_off(musb->phy);
    485	phy_exit(musb->phy);
    486	glue->phy_suspended = 1;
    487
    488	return 0;
    489}
    490
    491/* Glue layer needs to be suspended after musb_suspend() */
    492static int omap2430_suspend_late(struct device *dev)
    493{
    494	struct omap2430_glue *glue = dev_get_drvdata(dev);
    495
    496	if (glue->is_runtime_suspended)
    497		return 0;
    498
    499	glue->needs_resume = 1;
    500
    501	return omap2430_runtime_suspend(dev);
    502}
    503
    504static int omap2430_resume_early(struct device *dev)
    505{
    506	struct omap2430_glue *glue = dev_get_drvdata(dev);
    507
    508	if (!glue->needs_resume)
    509		return 0;
    510
    511	glue->needs_resume = 0;
    512
    513	return omap2430_runtime_resume(dev);
    514}
    515
    516static int omap2430_resume(struct device *dev)
    517{
    518	struct omap2430_glue *glue = dev_get_drvdata(dev);
    519	struct musb *musb = glue_to_musb(glue);
    520
    521	phy_init(musb->phy);
    522	phy_power_on(musb->phy);
    523	glue->phy_suspended = 0;
    524
    525	return 0;
    526}
    527
    528static const struct dev_pm_ops omap2430_pm_ops = {
    529	.runtime_suspend = omap2430_runtime_suspend,
    530	.runtime_resume = omap2430_runtime_resume,
    531	.suspend = omap2430_suspend,
    532	.suspend_late = omap2430_suspend_late,
    533	.resume_early = omap2430_resume_early,
    534	.resume = omap2430_resume,
    535};
    536
    537#define DEV_PM_OPS	(&omap2430_pm_ops)
    538#else
    539#define DEV_PM_OPS	NULL
    540#endif
    541
    542#ifdef CONFIG_OF
    543static const struct of_device_id omap2430_id_table[] = {
    544	{
    545		.compatible = "ti,omap4-musb"
    546	},
    547	{
    548		.compatible = "ti,omap3-musb"
    549	},
    550	{},
    551};
    552MODULE_DEVICE_TABLE(of, omap2430_id_table);
    553#endif
    554
    555static struct platform_driver omap2430_driver = {
    556	.probe		= omap2430_probe,
    557	.remove		= omap2430_remove,
    558	.driver		= {
    559		.name	= "musb-omap2430",
    560		.pm	= DEV_PM_OPS,
    561		.of_match_table = of_match_ptr(omap2430_id_table),
    562	},
    563};
    564
    565module_platform_driver(omap2430_driver);
    566
    567MODULE_DESCRIPTION("OMAP2PLUS MUSB Glue Layer");
    568MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
    569MODULE_LICENSE("GPL v2");