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

cdns3-ti.c (5708B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * cdns3-ti.c - TI specific Glue layer for Cadence USB Controller
      4 *
      5 * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com
      6 */
      7
      8#include <linux/bits.h>
      9#include <linux/clk.h>
     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/pm_runtime.h>
     18
     19/* USB Wrapper register offsets */
     20#define USBSS_PID		0x0
     21#define	USBSS_W1		0x4
     22#define USBSS_STATIC_CONFIG	0x8
     23#define USBSS_PHY_TEST		0xc
     24#define	USBSS_DEBUG_CTRL	0x10
     25#define	USBSS_DEBUG_INFO	0x14
     26#define	USBSS_DEBUG_LINK_STATE	0x18
     27#define	USBSS_DEVICE_CTRL	0x1c
     28
     29/* Wrapper 1 register bits */
     30#define USBSS_W1_PWRUP_RST		BIT(0)
     31#define USBSS_W1_OVERCURRENT_SEL	BIT(8)
     32#define USBSS_W1_MODESTRAP_SEL		BIT(9)
     33#define USBSS_W1_OVERCURRENT		BIT(16)
     34#define USBSS_W1_MODESTRAP_MASK		GENMASK(18, 17)
     35#define USBSS_W1_MODESTRAP_SHIFT	17
     36#define USBSS_W1_USB2_ONLY		BIT(19)
     37
     38/* Static config register bits */
     39#define USBSS1_STATIC_PLL_REF_SEL_MASK	GENMASK(8, 5)
     40#define USBSS1_STATIC_PLL_REF_SEL_SHIFT	5
     41#define USBSS1_STATIC_LOOPBACK_MODE_MASK	GENMASK(4, 3)
     42#define USBSS1_STATIC_LOOPBACK_MODE_SHIFT	3
     43#define USBSS1_STATIC_VBUS_SEL_MASK	GENMASK(2, 1)
     44#define USBSS1_STATIC_VBUS_SEL_SHIFT	1
     45#define USBSS1_STATIC_LANE_REVERSE	BIT(0)
     46
     47/* Modestrap modes */
     48enum modestrap_mode { USBSS_MODESTRAP_MODE_NONE,
     49		      USBSS_MODESTRAP_MODE_HOST,
     50		      USBSS_MODESTRAP_MODE_PERIPHERAL};
     51
     52struct cdns_ti {
     53	struct device *dev;
     54	void __iomem *usbss;
     55	unsigned usb2_only:1;
     56	unsigned vbus_divider:1;
     57	struct clk *usb2_refclk;
     58	struct clk *lpm_clk;
     59};
     60
     61static const int cdns_ti_rate_table[] = {	/* in KHZ */
     62	9600,
     63	10000,
     64	12000,
     65	19200,
     66	20000,
     67	24000,
     68	25000,
     69	26000,
     70	38400,
     71	40000,
     72	58000,
     73	50000,
     74	52000,
     75};
     76
     77static inline u32 cdns_ti_readl(struct cdns_ti *data, u32 offset)
     78{
     79	return readl(data->usbss + offset);
     80}
     81
     82static inline void cdns_ti_writel(struct cdns_ti *data, u32 offset, u32 value)
     83{
     84	writel(value, data->usbss + offset);
     85}
     86
     87static int cdns_ti_probe(struct platform_device *pdev)
     88{
     89	struct device *dev = &pdev->dev;
     90	struct device_node *node = pdev->dev.of_node;
     91	struct cdns_ti *data;
     92	int error;
     93	u32 reg;
     94	int rate_code, i;
     95	unsigned long rate;
     96
     97	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
     98	if (!data)
     99		return -ENOMEM;
    100
    101	platform_set_drvdata(pdev, data);
    102
    103	data->dev = dev;
    104
    105	data->usbss = devm_platform_ioremap_resource(pdev, 0);
    106	if (IS_ERR(data->usbss)) {
    107		dev_err(dev, "can't map IOMEM resource\n");
    108		return PTR_ERR(data->usbss);
    109	}
    110
    111	data->usb2_refclk = devm_clk_get(dev, "ref");
    112	if (IS_ERR(data->usb2_refclk)) {
    113		dev_err(dev, "can't get usb2_refclk\n");
    114		return PTR_ERR(data->usb2_refclk);
    115	}
    116
    117	data->lpm_clk = devm_clk_get(dev, "lpm");
    118	if (IS_ERR(data->lpm_clk)) {
    119		dev_err(dev, "can't get lpm_clk\n");
    120		return PTR_ERR(data->lpm_clk);
    121	}
    122
    123	rate = clk_get_rate(data->usb2_refclk);
    124	rate /= 1000;	/* To KHz */
    125	for (i = 0; i < ARRAY_SIZE(cdns_ti_rate_table); i++) {
    126		if (cdns_ti_rate_table[i] == rate)
    127			break;
    128	}
    129
    130	if (i == ARRAY_SIZE(cdns_ti_rate_table)) {
    131		dev_err(dev, "unsupported usb2_refclk rate: %lu KHz\n", rate);
    132		return -EINVAL;
    133	}
    134
    135	rate_code = i;
    136
    137	pm_runtime_enable(dev);
    138	error = pm_runtime_get_sync(dev);
    139	if (error < 0) {
    140		dev_err(dev, "pm_runtime_get_sync failed: %d\n", error);
    141		goto err;
    142	}
    143
    144	/* assert RESET */
    145	reg = cdns_ti_readl(data, USBSS_W1);
    146	reg &= ~USBSS_W1_PWRUP_RST;
    147	cdns_ti_writel(data, USBSS_W1, reg);
    148
    149	/* set static config */
    150	reg = cdns_ti_readl(data, USBSS_STATIC_CONFIG);
    151	reg &= ~USBSS1_STATIC_PLL_REF_SEL_MASK;
    152	reg |= rate_code << USBSS1_STATIC_PLL_REF_SEL_SHIFT;
    153
    154	reg &= ~USBSS1_STATIC_VBUS_SEL_MASK;
    155	data->vbus_divider = device_property_read_bool(dev, "ti,vbus-divider");
    156	if (data->vbus_divider)
    157		reg |= 1 << USBSS1_STATIC_VBUS_SEL_SHIFT;
    158
    159	cdns_ti_writel(data, USBSS_STATIC_CONFIG, reg);
    160	reg = cdns_ti_readl(data, USBSS_STATIC_CONFIG);
    161
    162	/* set USB2_ONLY mode if requested */
    163	reg = cdns_ti_readl(data, USBSS_W1);
    164	data->usb2_only = device_property_read_bool(dev, "ti,usb2-only");
    165	if (data->usb2_only)
    166		reg |= USBSS_W1_USB2_ONLY;
    167
    168	/* set default modestrap */
    169	reg |= USBSS_W1_MODESTRAP_SEL;
    170	reg &= ~USBSS_W1_MODESTRAP_MASK;
    171	reg |= USBSS_MODESTRAP_MODE_NONE << USBSS_W1_MODESTRAP_SHIFT;
    172	cdns_ti_writel(data, USBSS_W1, reg);
    173
    174	/* de-assert RESET */
    175	reg |= USBSS_W1_PWRUP_RST;
    176	cdns_ti_writel(data, USBSS_W1, reg);
    177
    178	error = of_platform_populate(node, NULL, NULL, dev);
    179	if (error) {
    180		dev_err(dev, "failed to create children: %d\n", error);
    181		goto err;
    182	}
    183
    184	return 0;
    185
    186err:
    187	pm_runtime_put_sync(data->dev);
    188	pm_runtime_disable(data->dev);
    189
    190	return error;
    191}
    192
    193static int cdns_ti_remove_core(struct device *dev, void *c)
    194{
    195	struct platform_device *pdev = to_platform_device(dev);
    196
    197	platform_device_unregister(pdev);
    198
    199	return 0;
    200}
    201
    202static int cdns_ti_remove(struct platform_device *pdev)
    203{
    204	struct device *dev = &pdev->dev;
    205
    206	device_for_each_child(dev, NULL, cdns_ti_remove_core);
    207	pm_runtime_put_sync(dev);
    208	pm_runtime_disable(dev);
    209
    210	platform_set_drvdata(pdev, NULL);
    211
    212	return 0;
    213}
    214
    215static const struct of_device_id cdns_ti_of_match[] = {
    216	{ .compatible = "ti,j721e-usb", },
    217	{ .compatible = "ti,am64-usb", },
    218	{},
    219};
    220MODULE_DEVICE_TABLE(of, cdns_ti_of_match);
    221
    222static struct platform_driver cdns_ti_driver = {
    223	.probe		= cdns_ti_probe,
    224	.remove		= cdns_ti_remove,
    225	.driver		= {
    226		.name	= "cdns3-ti",
    227		.of_match_table	= cdns_ti_of_match,
    228	},
    229};
    230
    231module_platform_driver(cdns_ti_driver);
    232
    233MODULE_ALIAS("platform:cdns3-ti");
    234MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
    235MODULE_LICENSE("GPL v2");
    236MODULE_DESCRIPTION("Cadence USB3 TI Glue Layer");