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

dwc3-keystone.c (5490B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * dwc3-keystone.c - Keystone Specific Glue layer
      4 *
      5 * Copyright (C) 2010-2013 Texas Instruments Incorporated - https://www.ti.com
      6 *
      7 * Author: WingMan Kwok <w-kwok2@ti.com>
      8 */
      9
     10#include <linux/module.h>
     11#include <linux/kernel.h>
     12#include <linux/interrupt.h>
     13#include <linux/platform_device.h>
     14#include <linux/dma-mapping.h>
     15#include <linux/io.h>
     16#include <linux/of_platform.h>
     17#include <linux/phy/phy.h>
     18#include <linux/pm_runtime.h>
     19
     20/* USBSS register offsets */
     21#define USBSS_REVISION		0x0000
     22#define USBSS_SYSCONFIG		0x0010
     23#define USBSS_IRQ_EOI		0x0018
     24#define USBSS_IRQSTATUS_RAW_0	0x0020
     25#define USBSS_IRQSTATUS_0	0x0024
     26#define USBSS_IRQENABLE_SET_0	0x0028
     27#define USBSS_IRQENABLE_CLR_0	0x002c
     28
     29/* IRQ register bits */
     30#define USBSS_IRQ_EOI_LINE(n)	BIT(n)
     31#define USBSS_IRQ_EVENT_ST	BIT(0)
     32#define USBSS_IRQ_COREIRQ_EN	BIT(0)
     33#define USBSS_IRQ_COREIRQ_CLR	BIT(0)
     34
     35struct dwc3_keystone {
     36	struct device			*dev;
     37	void __iomem			*usbss;
     38	struct phy			*usb3_phy;
     39};
     40
     41static inline u32 kdwc3_readl(void __iomem *base, u32 offset)
     42{
     43	return readl(base + offset);
     44}
     45
     46static inline void kdwc3_writel(void __iomem *base, u32 offset, u32 value)
     47{
     48	writel(value, base + offset);
     49}
     50
     51static void kdwc3_enable_irqs(struct dwc3_keystone *kdwc)
     52{
     53	u32 val;
     54
     55	val = kdwc3_readl(kdwc->usbss, USBSS_IRQENABLE_SET_0);
     56	val |= USBSS_IRQ_COREIRQ_EN;
     57	kdwc3_writel(kdwc->usbss, USBSS_IRQENABLE_SET_0, val);
     58}
     59
     60static void kdwc3_disable_irqs(struct dwc3_keystone *kdwc)
     61{
     62	u32 val;
     63
     64	val = kdwc3_readl(kdwc->usbss, USBSS_IRQENABLE_SET_0);
     65	val &= ~USBSS_IRQ_COREIRQ_EN;
     66	kdwc3_writel(kdwc->usbss, USBSS_IRQENABLE_SET_0, val);
     67}
     68
     69static irqreturn_t dwc3_keystone_interrupt(int irq, void *_kdwc)
     70{
     71	struct dwc3_keystone	*kdwc = _kdwc;
     72
     73	kdwc3_writel(kdwc->usbss, USBSS_IRQENABLE_CLR_0, USBSS_IRQ_COREIRQ_CLR);
     74	kdwc3_writel(kdwc->usbss, USBSS_IRQSTATUS_0, USBSS_IRQ_EVENT_ST);
     75	kdwc3_writel(kdwc->usbss, USBSS_IRQENABLE_SET_0, USBSS_IRQ_COREIRQ_EN);
     76	kdwc3_writel(kdwc->usbss, USBSS_IRQ_EOI, USBSS_IRQ_EOI_LINE(0));
     77
     78	return IRQ_HANDLED;
     79}
     80
     81static int kdwc3_probe(struct platform_device *pdev)
     82{
     83	struct device		*dev = &pdev->dev;
     84	struct device_node	*node = pdev->dev.of_node;
     85	struct dwc3_keystone	*kdwc;
     86	int			error, irq;
     87
     88	kdwc = devm_kzalloc(dev, sizeof(*kdwc), GFP_KERNEL);
     89	if (!kdwc)
     90		return -ENOMEM;
     91
     92	platform_set_drvdata(pdev, kdwc);
     93
     94	kdwc->dev = dev;
     95
     96	kdwc->usbss = devm_platform_ioremap_resource(pdev, 0);
     97	if (IS_ERR(kdwc->usbss))
     98		return PTR_ERR(kdwc->usbss);
     99
    100	/* PSC dependency on AM65 needs SERDES0 to be powered before USB0 */
    101	kdwc->usb3_phy = devm_phy_optional_get(dev, "usb3-phy");
    102	if (IS_ERR(kdwc->usb3_phy))
    103		return dev_err_probe(dev, PTR_ERR(kdwc->usb3_phy), "couldn't get usb3 phy\n");
    104
    105	phy_pm_runtime_get_sync(kdwc->usb3_phy);
    106
    107	error = phy_reset(kdwc->usb3_phy);
    108	if (error < 0) {
    109		dev_err(dev, "usb3 phy reset failed: %d\n", error);
    110		return error;
    111	}
    112
    113	error = phy_init(kdwc->usb3_phy);
    114	if (error < 0) {
    115		dev_err(dev, "usb3 phy init failed: %d\n", error);
    116		return error;
    117	}
    118
    119	error = phy_power_on(kdwc->usb3_phy);
    120	if (error < 0) {
    121		dev_err(dev, "usb3 phy power on failed: %d\n", error);
    122		phy_exit(kdwc->usb3_phy);
    123		return error;
    124	}
    125
    126	pm_runtime_enable(kdwc->dev);
    127	error = pm_runtime_get_sync(kdwc->dev);
    128	if (error < 0) {
    129		dev_err(kdwc->dev, "pm_runtime_get_sync failed, error %d\n",
    130			error);
    131		goto err_irq;
    132	}
    133
    134	/* IRQ processing not required currently for AM65 */
    135	if (of_device_is_compatible(node, "ti,am654-dwc3"))
    136		goto skip_irq;
    137
    138	irq = platform_get_irq(pdev, 0);
    139	if (irq < 0) {
    140		error = irq;
    141		goto err_irq;
    142	}
    143
    144	error = devm_request_irq(dev, irq, dwc3_keystone_interrupt, IRQF_SHARED,
    145			dev_name(dev), kdwc);
    146	if (error) {
    147		dev_err(dev, "failed to request IRQ #%d --> %d\n",
    148				irq, error);
    149		goto err_irq;
    150	}
    151
    152	kdwc3_enable_irqs(kdwc);
    153
    154skip_irq:
    155	error = of_platform_populate(node, NULL, NULL, dev);
    156	if (error) {
    157		dev_err(&pdev->dev, "failed to create dwc3 core\n");
    158		goto err_core;
    159	}
    160
    161	return 0;
    162
    163err_core:
    164	kdwc3_disable_irqs(kdwc);
    165err_irq:
    166	pm_runtime_put_sync(kdwc->dev);
    167	pm_runtime_disable(kdwc->dev);
    168	phy_power_off(kdwc->usb3_phy);
    169	phy_exit(kdwc->usb3_phy);
    170	phy_pm_runtime_put_sync(kdwc->usb3_phy);
    171
    172	return error;
    173}
    174
    175static int kdwc3_remove_core(struct device *dev, void *c)
    176{
    177	struct platform_device *pdev = to_platform_device(dev);
    178
    179	platform_device_unregister(pdev);
    180
    181	return 0;
    182}
    183
    184static int kdwc3_remove(struct platform_device *pdev)
    185{
    186	struct dwc3_keystone *kdwc = platform_get_drvdata(pdev);
    187	struct device_node *node = pdev->dev.of_node;
    188
    189	if (!of_device_is_compatible(node, "ti,am654-dwc3"))
    190		kdwc3_disable_irqs(kdwc);
    191
    192	device_for_each_child(&pdev->dev, NULL, kdwc3_remove_core);
    193	pm_runtime_put_sync(kdwc->dev);
    194	pm_runtime_disable(kdwc->dev);
    195
    196	phy_power_off(kdwc->usb3_phy);
    197	phy_exit(kdwc->usb3_phy);
    198	phy_pm_runtime_put_sync(kdwc->usb3_phy);
    199
    200	platform_set_drvdata(pdev, NULL);
    201
    202	return 0;
    203}
    204
    205static const struct of_device_id kdwc3_of_match[] = {
    206	{ .compatible = "ti,keystone-dwc3", },
    207	{ .compatible = "ti,am654-dwc3" },
    208	{},
    209};
    210MODULE_DEVICE_TABLE(of, kdwc3_of_match);
    211
    212static struct platform_driver kdwc3_driver = {
    213	.probe		= kdwc3_probe,
    214	.remove		= kdwc3_remove,
    215	.driver		= {
    216		.name	= "keystone-dwc3",
    217		.of_match_table	= kdwc3_of_match,
    218	},
    219};
    220
    221module_platform_driver(kdwc3_driver);
    222
    223MODULE_ALIAS("platform:keystone-dwc3");
    224MODULE_AUTHOR("WingMan Kwok <w-kwok2@ti.com>");
    225MODULE_LICENSE("GPL v2");
    226MODULE_DESCRIPTION("DesignWare USB3 KEYSTONE Glue Layer");