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

phy-rcar-gen3-usb3.c (5454B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Renesas R-Car Gen3 for USB3.0 PHY driver
      4 *
      5 * Copyright (C) 2017 Renesas Electronics Corporation
      6 */
      7
      8#include <linux/clk.h>
      9#include <linux/delay.h>
     10#include <linux/io.h>
     11#include <linux/module.h>
     12#include <linux/of.h>
     13#include <linux/phy/phy.h>
     14#include <linux/platform_device.h>
     15#include <linux/pm_runtime.h>
     16
     17#define USB30_CLKSET0		0x034
     18#define USB30_CLKSET1		0x036
     19#define USB30_SSC_SET		0x038
     20#define USB30_PHY_ENABLE	0x060
     21#define USB30_VBUS_EN		0x064
     22
     23/* USB30_CLKSET0 */
     24#define CLKSET0_PRIVATE			0x05c0
     25#define CLKSET0_USB30_FSEL_USB_EXTAL	0x0002
     26
     27/* USB30_CLKSET1 */
     28#define CLKSET1_USB30_PLL_MULTI_SHIFT		6
     29#define CLKSET1_USB30_PLL_MULTI_USB_EXTAL	(0x64 << \
     30						 CLKSET1_USB30_PLL_MULTI_SHIFT)
     31#define CLKSET1_PHYRESET	BIT(4)	/* 1: reset */
     32#define CLKSET1_REF_CLKDIV	BIT(3)	/* 1: USB_EXTAL */
     33#define CLKSET1_PRIVATE_2_1	BIT(1)	/* Write B'01 */
     34#define CLKSET1_REF_CLK_SEL	BIT(0)	/* 1: USB3S0_CLK_P */
     35
     36/* USB30_SSC_SET */
     37#define SSC_SET_SSC_EN		BIT(12)
     38#define SSC_SET_RANGE_SHIFT	9
     39#define SSC_SET_RANGE_4980	(0x0 << SSC_SET_RANGE_SHIFT)
     40#define SSC_SET_RANGE_4492	(0x1 << SSC_SET_RANGE_SHIFT)
     41#define SSC_SET_RANGE_4003	(0x2 << SSC_SET_RANGE_SHIFT)
     42
     43/* USB30_PHY_ENABLE */
     44#define PHY_ENABLE_RESET_EN	BIT(4)
     45
     46/* USB30_VBUS_EN */
     47#define VBUS_EN_VBUS_EN		BIT(1)
     48
     49struct rcar_gen3_usb3 {
     50	void __iomem *base;
     51	struct phy *phy;
     52	u32 ssc_range;
     53	bool usb3s_clk;
     54	bool usb_extal;
     55};
     56
     57static void write_clkset1_for_usb_extal(struct rcar_gen3_usb3 *r, bool reset)
     58{
     59	u16 val = CLKSET1_USB30_PLL_MULTI_USB_EXTAL |
     60		  CLKSET1_REF_CLKDIV | CLKSET1_PRIVATE_2_1;
     61
     62	if (reset)
     63		val |= CLKSET1_PHYRESET;
     64
     65	writew(val, r->base + USB30_CLKSET1);
     66}
     67
     68static void rcar_gen3_phy_usb3_enable_ssc(struct rcar_gen3_usb3 *r)
     69{
     70	u16 val = SSC_SET_SSC_EN;
     71
     72	switch (r->ssc_range) {
     73	case 4980:
     74		val |= SSC_SET_RANGE_4980;
     75		break;
     76	case 4492:
     77		val |= SSC_SET_RANGE_4492;
     78		break;
     79	case 4003:
     80		val |= SSC_SET_RANGE_4003;
     81		break;
     82	default:
     83		dev_err(&r->phy->dev, "%s: unsupported range (%x)\n", __func__,
     84			r->ssc_range);
     85		return;
     86	}
     87
     88	writew(val, r->base + USB30_SSC_SET);
     89}
     90
     91static void rcar_gen3_phy_usb3_select_usb_extal(struct rcar_gen3_usb3 *r)
     92{
     93	write_clkset1_for_usb_extal(r, false);
     94	if (r->ssc_range)
     95		rcar_gen3_phy_usb3_enable_ssc(r);
     96	writew(CLKSET0_PRIVATE | CLKSET0_USB30_FSEL_USB_EXTAL,
     97	       r->base + USB30_CLKSET0);
     98	writew(PHY_ENABLE_RESET_EN, r->base + USB30_PHY_ENABLE);
     99	write_clkset1_for_usb_extal(r, true);
    100	usleep_range(10, 20);
    101	write_clkset1_for_usb_extal(r, false);
    102}
    103
    104static int rcar_gen3_phy_usb3_init(struct phy *p)
    105{
    106	struct rcar_gen3_usb3 *r = phy_get_drvdata(p);
    107
    108	dev_vdbg(&r->phy->dev, "%s: enter (%d, %d, %d)\n", __func__,
    109		 r->usb3s_clk, r->usb_extal, r->ssc_range);
    110
    111	if (!r->usb3s_clk && r->usb_extal)
    112		rcar_gen3_phy_usb3_select_usb_extal(r);
    113
    114	/* Enables VBUS detection anyway */
    115	writew(VBUS_EN_VBUS_EN, r->base + USB30_VBUS_EN);
    116
    117	return 0;
    118}
    119
    120static const struct phy_ops rcar_gen3_phy_usb3_ops = {
    121	.init		= rcar_gen3_phy_usb3_init,
    122	.owner		= THIS_MODULE,
    123};
    124
    125static const struct of_device_id rcar_gen3_phy_usb3_match_table[] = {
    126	{ .compatible = "renesas,rcar-gen3-usb3-phy" },
    127	{ }
    128};
    129MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb3_match_table);
    130
    131static int rcar_gen3_phy_usb3_probe(struct platform_device *pdev)
    132{
    133	struct device *dev = &pdev->dev;
    134	struct rcar_gen3_usb3 *r;
    135	struct phy_provider *provider;
    136	int ret = 0;
    137	struct clk *clk;
    138
    139	if (!dev->of_node) {
    140		dev_err(dev, "This driver needs device tree\n");
    141		return -EINVAL;
    142	}
    143
    144	r = devm_kzalloc(dev, sizeof(*r), GFP_KERNEL);
    145	if (!r)
    146		return -ENOMEM;
    147
    148	r->base = devm_platform_ioremap_resource(pdev, 0);
    149	if (IS_ERR(r->base))
    150		return PTR_ERR(r->base);
    151
    152	clk = devm_clk_get(dev, "usb3s_clk");
    153	if (!IS_ERR(clk) && !clk_prepare_enable(clk)) {
    154		r->usb3s_clk = !!clk_get_rate(clk);
    155		clk_disable_unprepare(clk);
    156	}
    157	clk = devm_clk_get(dev, "usb_extal");
    158	if (!IS_ERR(clk) && !clk_prepare_enable(clk)) {
    159		r->usb_extal = !!clk_get_rate(clk);
    160		clk_disable_unprepare(clk);
    161	}
    162
    163	if (!r->usb3s_clk && !r->usb_extal) {
    164		dev_err(dev, "This driver needs usb3s_clk and/or usb_extal\n");
    165		ret = -EINVAL;
    166		goto error;
    167	}
    168
    169	/*
    170	 * devm_phy_create() will call pm_runtime_enable(&phy->dev);
    171	 * And then, phy-core will manage runtime pm for this device.
    172	 */
    173	pm_runtime_enable(dev);
    174
    175	r->phy = devm_phy_create(dev, NULL, &rcar_gen3_phy_usb3_ops);
    176	if (IS_ERR(r->phy)) {
    177		dev_err(dev, "Failed to create USB3 PHY\n");
    178		ret = PTR_ERR(r->phy);
    179		goto error;
    180	}
    181
    182	of_property_read_u32(dev->of_node, "renesas,ssc-range", &r->ssc_range);
    183
    184	platform_set_drvdata(pdev, r);
    185	phy_set_drvdata(r->phy, r);
    186
    187	provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
    188	if (IS_ERR(provider)) {
    189		dev_err(dev, "Failed to register PHY provider\n");
    190		ret = PTR_ERR(provider);
    191		goto error;
    192	}
    193
    194	return 0;
    195
    196error:
    197	pm_runtime_disable(dev);
    198
    199	return ret;
    200}
    201
    202static int rcar_gen3_phy_usb3_remove(struct platform_device *pdev)
    203{
    204	pm_runtime_disable(&pdev->dev);
    205
    206	return 0;
    207};
    208
    209static struct platform_driver rcar_gen3_phy_usb3_driver = {
    210	.driver = {
    211		.name		= "phy_rcar_gen3_usb3",
    212		.of_match_table	= rcar_gen3_phy_usb3_match_table,
    213	},
    214	.probe	= rcar_gen3_phy_usb3_probe,
    215	.remove = rcar_gen3_phy_usb3_remove,
    216};
    217module_platform_driver(rcar_gen3_phy_usb3_driver);
    218
    219MODULE_LICENSE("GPL v2");
    220MODULE_DESCRIPTION("Renesas R-Car Gen3 USB 3.0 PHY");
    221MODULE_AUTHOR("Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>");