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-pistachio-usb.c (5121B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * IMG Pistachio USB PHY driver
      4 *
      5 * Copyright (C) 2015 Google, Inc.
      6 */
      7
      8#include <linux/clk.h>
      9#include <linux/delay.h>
     10#include <linux/io.h>
     11#include <linux/kernel.h>
     12#include <linux/mfd/syscon.h>
     13#include <linux/module.h>
     14#include <linux/of.h>
     15#include <linux/phy/phy.h>
     16#include <linux/platform_device.h>
     17#include <linux/regmap.h>
     18
     19#include <dt-bindings/phy/phy-pistachio-usb.h>
     20
     21#define USB_PHY_CONTROL1				0x04
     22#define USB_PHY_CONTROL1_FSEL_SHIFT			2
     23#define USB_PHY_CONTROL1_FSEL_MASK			0x7
     24
     25#define USB_PHY_STRAP_CONTROL				0x10
     26#define USB_PHY_STRAP_CONTROL_REFCLK_SHIFT		4
     27#define USB_PHY_STRAP_CONTROL_REFCLK_MASK		0x3
     28
     29#define USB_PHY_STATUS					0x14
     30#define USB_PHY_STATUS_RX_PHY_CLK			BIT(9)
     31#define USB_PHY_STATUS_RX_UTMI_CLK			BIT(8)
     32#define USB_PHY_STATUS_VBUS_FAULT			BIT(7)
     33
     34struct pistachio_usb_phy {
     35	struct device *dev;
     36	struct regmap *cr_top;
     37	struct clk *phy_clk;
     38	unsigned int refclk;
     39};
     40
     41static const unsigned long fsel_rate_map[] = {
     42	9600000,
     43	10000000,
     44	12000000,
     45	19200000,
     46	20000000,
     47	24000000,
     48	0,
     49	50000000,
     50};
     51
     52static int pistachio_usb_phy_power_on(struct phy *phy)
     53{
     54	struct pistachio_usb_phy *p_phy = phy_get_drvdata(phy);
     55	unsigned long timeout, rate;
     56	unsigned int i;
     57	int ret;
     58
     59	ret = clk_prepare_enable(p_phy->phy_clk);
     60	if (ret < 0) {
     61		dev_err(p_phy->dev, "Failed to enable PHY clock: %d\n", ret);
     62		return ret;
     63	}
     64
     65	regmap_update_bits(p_phy->cr_top, USB_PHY_STRAP_CONTROL,
     66			   USB_PHY_STRAP_CONTROL_REFCLK_MASK <<
     67			   USB_PHY_STRAP_CONTROL_REFCLK_SHIFT,
     68			   p_phy->refclk << USB_PHY_STRAP_CONTROL_REFCLK_SHIFT);
     69
     70	rate = clk_get_rate(p_phy->phy_clk);
     71	if (p_phy->refclk == REFCLK_XO_CRYSTAL && rate != 12000000) {
     72		dev_err(p_phy->dev, "Unsupported rate for XO crystal: %ld\n",
     73			rate);
     74		ret = -EINVAL;
     75		goto disable_clk;
     76	}
     77
     78	for (i = 0; i < ARRAY_SIZE(fsel_rate_map); i++) {
     79		if (rate == fsel_rate_map[i])
     80			break;
     81	}
     82	if (i == ARRAY_SIZE(fsel_rate_map)) {
     83		dev_err(p_phy->dev, "Unsupported clock rate: %lu\n", rate);
     84		ret = -EINVAL;
     85		goto disable_clk;
     86	}
     87
     88	regmap_update_bits(p_phy->cr_top, USB_PHY_CONTROL1,
     89			   USB_PHY_CONTROL1_FSEL_MASK <<
     90			   USB_PHY_CONTROL1_FSEL_SHIFT,
     91			   i << USB_PHY_CONTROL1_FSEL_SHIFT);
     92
     93	timeout = jiffies + msecs_to_jiffies(200);
     94	while (time_before(jiffies, timeout)) {
     95		unsigned int val;
     96
     97		regmap_read(p_phy->cr_top, USB_PHY_STATUS, &val);
     98		if (val & USB_PHY_STATUS_VBUS_FAULT) {
     99			dev_err(p_phy->dev, "VBUS fault detected\n");
    100			ret = -EIO;
    101			goto disable_clk;
    102		}
    103		if ((val & USB_PHY_STATUS_RX_PHY_CLK) &&
    104		    (val & USB_PHY_STATUS_RX_UTMI_CLK))
    105			return 0;
    106		usleep_range(1000, 1500);
    107	}
    108
    109	dev_err(p_phy->dev, "Timed out waiting for PHY to power on\n");
    110	ret = -ETIMEDOUT;
    111
    112disable_clk:
    113	clk_disable_unprepare(p_phy->phy_clk);
    114	return ret;
    115}
    116
    117static int pistachio_usb_phy_power_off(struct phy *phy)
    118{
    119	struct pistachio_usb_phy *p_phy = phy_get_drvdata(phy);
    120
    121	clk_disable_unprepare(p_phy->phy_clk);
    122
    123	return 0;
    124}
    125
    126static const struct phy_ops pistachio_usb_phy_ops = {
    127	.power_on = pistachio_usb_phy_power_on,
    128	.power_off = pistachio_usb_phy_power_off,
    129	.owner = THIS_MODULE,
    130};
    131
    132static int pistachio_usb_phy_probe(struct platform_device *pdev)
    133{
    134	struct pistachio_usb_phy *p_phy;
    135	struct phy_provider *provider;
    136	struct phy *phy;
    137	int ret;
    138
    139	p_phy = devm_kzalloc(&pdev->dev, sizeof(*p_phy), GFP_KERNEL);
    140	if (!p_phy)
    141		return -ENOMEM;
    142	p_phy->dev = &pdev->dev;
    143	platform_set_drvdata(pdev, p_phy);
    144
    145	p_phy->cr_top = syscon_regmap_lookup_by_phandle(p_phy->dev->of_node,
    146							"img,cr-top");
    147	if (IS_ERR(p_phy->cr_top)) {
    148		dev_err(p_phy->dev, "Failed to get CR_TOP registers: %ld\n",
    149			PTR_ERR(p_phy->cr_top));
    150		return PTR_ERR(p_phy->cr_top);
    151	}
    152
    153	p_phy->phy_clk = devm_clk_get(p_phy->dev, "usb_phy");
    154	if (IS_ERR(p_phy->phy_clk)) {
    155		dev_err(p_phy->dev, "Failed to get usb_phy clock: %ld\n",
    156			PTR_ERR(p_phy->phy_clk));
    157		return PTR_ERR(p_phy->phy_clk);
    158	}
    159
    160	ret = of_property_read_u32(p_phy->dev->of_node, "img,refclk",
    161				   &p_phy->refclk);
    162	if (ret < 0) {
    163		dev_err(p_phy->dev, "No reference clock selector specified\n");
    164		return ret;
    165	}
    166
    167	phy = devm_phy_create(p_phy->dev, NULL, &pistachio_usb_phy_ops);
    168	if (IS_ERR(phy)) {
    169		dev_err(p_phy->dev, "Failed to create PHY: %ld\n",
    170			PTR_ERR(phy));
    171		return PTR_ERR(phy);
    172	}
    173	phy_set_drvdata(phy, p_phy);
    174
    175	provider = devm_of_phy_provider_register(p_phy->dev,
    176						 of_phy_simple_xlate);
    177	if (IS_ERR(provider)) {
    178		dev_err(p_phy->dev, "Failed to register PHY provider: %ld\n",
    179			PTR_ERR(provider));
    180		return PTR_ERR(provider);
    181	}
    182
    183	return 0;
    184}
    185
    186static const struct of_device_id pistachio_usb_phy_of_match[] = {
    187	{ .compatible = "img,pistachio-usb-phy", },
    188	{ },
    189};
    190MODULE_DEVICE_TABLE(of, pistachio_usb_phy_of_match);
    191
    192static struct platform_driver pistachio_usb_phy_driver = {
    193	.probe		= pistachio_usb_phy_probe,
    194	.driver		= {
    195		.name	= "pistachio-usb-phy",
    196		.of_match_table = pistachio_usb_phy_of_match,
    197	},
    198};
    199module_platform_driver(pistachio_usb_phy_driver);
    200
    201MODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>");
    202MODULE_DESCRIPTION("IMG Pistachio USB2.0 PHY driver");
    203MODULE_LICENSE("GPL v2");