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-am335x-control.c (4407B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <linux/module.h>
      3#include <linux/platform_device.h>
      4#include <linux/err.h>
      5#include <linux/of.h>
      6#include <linux/io.h>
      7#include <linux/delay.h>
      8#include <linux/usb/otg.h>
      9#include "phy-am335x-control.h"
     10
     11struct am335x_control_usb {
     12	struct device *dev;
     13	void __iomem *phy_reg;
     14	void __iomem *wkup;
     15	spinlock_t lock;
     16	struct phy_control phy_ctrl;
     17};
     18
     19#define AM335X_USB0_CTRL		0x0
     20#define AM335X_USB1_CTRL		0x8
     21#define AM335x_USB_WKUP			0x0
     22
     23#define USBPHY_CM_PWRDN		(1 << 0)
     24#define USBPHY_OTG_PWRDN	(1 << 1)
     25#define USBPHY_OTGVDET_EN	(1 << 19)
     26#define USBPHY_OTGSESSEND_EN	(1 << 20)
     27
     28#define AM335X_PHY0_WK_EN	(1 << 0)
     29#define AM335X_PHY1_WK_EN	(1 << 8)
     30
     31static void am335x_phy_wkup(struct  phy_control *phy_ctrl, u32 id, bool on)
     32{
     33	struct am335x_control_usb *usb_ctrl;
     34	u32 val;
     35	u32 reg;
     36
     37	usb_ctrl = container_of(phy_ctrl, struct am335x_control_usb, phy_ctrl);
     38
     39	switch (id) {
     40	case 0:
     41		reg = AM335X_PHY0_WK_EN;
     42		break;
     43	case 1:
     44		reg = AM335X_PHY1_WK_EN;
     45		break;
     46	default:
     47		WARN_ON(1);
     48		return;
     49	}
     50
     51	spin_lock(&usb_ctrl->lock);
     52	val = readl(usb_ctrl->wkup);
     53
     54	if (on)
     55		val |= reg;
     56	else
     57		val &= ~reg;
     58
     59	writel(val, usb_ctrl->wkup);
     60	spin_unlock(&usb_ctrl->lock);
     61}
     62
     63static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id,
     64				enum usb_dr_mode dr_mode, bool on)
     65{
     66	struct am335x_control_usb *usb_ctrl;
     67	u32 val;
     68	u32 reg;
     69
     70	usb_ctrl = container_of(phy_ctrl, struct am335x_control_usb, phy_ctrl);
     71
     72	switch (id) {
     73	case 0:
     74		reg = AM335X_USB0_CTRL;
     75		break;
     76	case 1:
     77		reg = AM335X_USB1_CTRL;
     78		break;
     79	default:
     80		WARN_ON(1);
     81		return;
     82	}
     83
     84	val = readl(usb_ctrl->phy_reg + reg);
     85	if (on) {
     86		if (dr_mode == USB_DR_MODE_HOST) {
     87			val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN |
     88					USBPHY_OTGVDET_EN);
     89			val |= USBPHY_OTGSESSEND_EN;
     90		} else {
     91			val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN);
     92			val |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN;
     93		}
     94	} else {
     95		val |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN;
     96	}
     97
     98	writel(val, usb_ctrl->phy_reg + reg);
     99
    100	/*
    101	 * Give the PHY ~1ms to complete the power up operation.
    102	 * Tests have shown unstable behaviour if other USB PHY related
    103	 * registers are written too shortly after such a transition.
    104	 */
    105	if (on)
    106		mdelay(1);
    107}
    108
    109static const struct phy_control ctrl_am335x = {
    110	.phy_power = am335x_phy_power,
    111	.phy_wkup = am335x_phy_wkup,
    112};
    113
    114static const struct of_device_id omap_control_usb_id_table[] = {
    115	{ .compatible = "ti,am335x-usb-ctrl-module", .data = &ctrl_am335x },
    116	{}
    117};
    118MODULE_DEVICE_TABLE(of, omap_control_usb_id_table);
    119
    120static struct platform_driver am335x_control_driver;
    121static int match(struct device *dev, const void *data)
    122{
    123	const struct device_node *node = (const struct device_node *)data;
    124	return dev->of_node == node &&
    125		dev->driver == &am335x_control_driver.driver;
    126}
    127
    128struct phy_control *am335x_get_phy_control(struct device *dev)
    129{
    130	struct device_node *node;
    131	struct am335x_control_usb *ctrl_usb;
    132
    133	node = of_parse_phandle(dev->of_node, "ti,ctrl_mod", 0);
    134	if (!node)
    135		return NULL;
    136
    137	dev = bus_find_device(&platform_bus_type, NULL, node, match);
    138	of_node_put(node);
    139	if (!dev)
    140		return NULL;
    141
    142	ctrl_usb = dev_get_drvdata(dev);
    143	put_device(dev);
    144	if (!ctrl_usb)
    145		return NULL;
    146	return &ctrl_usb->phy_ctrl;
    147}
    148EXPORT_SYMBOL_GPL(am335x_get_phy_control);
    149
    150static int am335x_control_usb_probe(struct platform_device *pdev)
    151{
    152	struct am335x_control_usb *ctrl_usb;
    153	const struct of_device_id *of_id;
    154	const struct phy_control *phy_ctrl;
    155
    156	of_id = of_match_node(omap_control_usb_id_table, pdev->dev.of_node);
    157	if (!of_id)
    158		return -EINVAL;
    159
    160	phy_ctrl = of_id->data;
    161
    162	ctrl_usb = devm_kzalloc(&pdev->dev, sizeof(*ctrl_usb), GFP_KERNEL);
    163	if (!ctrl_usb)
    164		return -ENOMEM;
    165
    166	ctrl_usb->dev = &pdev->dev;
    167
    168	ctrl_usb->phy_reg = devm_platform_ioremap_resource_byname(pdev, "phy_ctrl");
    169	if (IS_ERR(ctrl_usb->phy_reg))
    170		return PTR_ERR(ctrl_usb->phy_reg);
    171
    172	ctrl_usb->wkup = devm_platform_ioremap_resource_byname(pdev, "wakeup");
    173	if (IS_ERR(ctrl_usb->wkup))
    174		return PTR_ERR(ctrl_usb->wkup);
    175
    176	spin_lock_init(&ctrl_usb->lock);
    177	ctrl_usb->phy_ctrl = *phy_ctrl;
    178
    179	dev_set_drvdata(ctrl_usb->dev, ctrl_usb);
    180	return 0;
    181}
    182
    183static struct platform_driver am335x_control_driver = {
    184	.probe		= am335x_control_usb_probe,
    185	.driver		= {
    186		.name	= "am335x-control-usb",
    187		.of_match_table = omap_control_usb_id_table,
    188	},
    189};
    190
    191module_platform_driver(am335x_control_driver);
    192MODULE_LICENSE("GPL v2");