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-ulpi.c (6590B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Generic ULPI USB transceiver support
      4 *
      5 * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de>
      6 *
      7 * Based on sources from
      8 *
      9 *   Sascha Hauer <s.hauer@pengutronix.de>
     10 *   Freescale Semiconductors
     11 */
     12
     13#include <linux/kernel.h>
     14#include <linux/slab.h>
     15#include <linux/export.h>
     16#include <linux/usb.h>
     17#include <linux/usb/otg.h>
     18#include <linux/usb/ulpi.h>
     19
     20
     21struct ulpi_info {
     22	unsigned int	id;
     23	char		*name;
     24};
     25
     26#define ULPI_ID(vendor, product) (((vendor) << 16) | (product))
     27#define ULPI_INFO(_id, _name)		\
     28	{				\
     29		.id	= (_id),	\
     30		.name	= (_name),	\
     31	}
     32
     33/* ULPI hardcoded IDs, used for probing */
     34static struct ulpi_info ulpi_ids[] = {
     35	ULPI_INFO(ULPI_ID(0x04cc, 0x1504), "NXP ISP1504"),
     36	ULPI_INFO(ULPI_ID(0x0424, 0x0006), "SMSC USB331x"),
     37	ULPI_INFO(ULPI_ID(0x0424, 0x0007), "SMSC USB3320"),
     38	ULPI_INFO(ULPI_ID(0x0424, 0x0009), "SMSC USB334x"),
     39	ULPI_INFO(ULPI_ID(0x0451, 0x1507), "TI TUSB1210"),
     40};
     41
     42static int ulpi_set_otg_flags(struct usb_phy *phy)
     43{
     44	unsigned int flags = ULPI_OTG_CTRL_DP_PULLDOWN |
     45			     ULPI_OTG_CTRL_DM_PULLDOWN;
     46
     47	if (phy->flags & ULPI_OTG_ID_PULLUP)
     48		flags |= ULPI_OTG_CTRL_ID_PULLUP;
     49
     50	/*
     51	 * ULPI Specification rev.1.1 default
     52	 * for Dp/DmPulldown is enabled.
     53	 */
     54	if (phy->flags & ULPI_OTG_DP_PULLDOWN_DIS)
     55		flags &= ~ULPI_OTG_CTRL_DP_PULLDOWN;
     56
     57	if (phy->flags & ULPI_OTG_DM_PULLDOWN_DIS)
     58		flags &= ~ULPI_OTG_CTRL_DM_PULLDOWN;
     59
     60	if (phy->flags & ULPI_OTG_EXTVBUSIND)
     61		flags |= ULPI_OTG_CTRL_EXTVBUSIND;
     62
     63	return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL);
     64}
     65
     66static int ulpi_set_fc_flags(struct usb_phy *phy)
     67{
     68	unsigned int flags = 0;
     69
     70	/*
     71	 * ULPI Specification rev.1.1 default
     72	 * for XcvrSelect is Full Speed.
     73	 */
     74	if (phy->flags & ULPI_FC_HS)
     75		flags |= ULPI_FUNC_CTRL_HIGH_SPEED;
     76	else if (phy->flags & ULPI_FC_LS)
     77		flags |= ULPI_FUNC_CTRL_LOW_SPEED;
     78	else if (phy->flags & ULPI_FC_FS4LS)
     79		flags |= ULPI_FUNC_CTRL_FS4LS;
     80	else
     81		flags |= ULPI_FUNC_CTRL_FULL_SPEED;
     82
     83	if (phy->flags & ULPI_FC_TERMSEL)
     84		flags |= ULPI_FUNC_CTRL_TERMSELECT;
     85
     86	/*
     87	 * ULPI Specification rev.1.1 default
     88	 * for OpMode is Normal Operation.
     89	 */
     90	if (phy->flags & ULPI_FC_OP_NODRV)
     91		flags |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
     92	else if (phy->flags & ULPI_FC_OP_DIS_NRZI)
     93		flags |= ULPI_FUNC_CTRL_OPMODE_DISABLE_NRZI;
     94	else if (phy->flags & ULPI_FC_OP_NSYNC_NEOP)
     95		flags |= ULPI_FUNC_CTRL_OPMODE_NOSYNC_NOEOP;
     96	else
     97		flags |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
     98
     99	/*
    100	 * ULPI Specification rev.1.1 default
    101	 * for SuspendM is Powered.
    102	 */
    103	flags |= ULPI_FUNC_CTRL_SUSPENDM;
    104
    105	return usb_phy_io_write(phy, flags, ULPI_FUNC_CTRL);
    106}
    107
    108static int ulpi_set_ic_flags(struct usb_phy *phy)
    109{
    110	unsigned int flags = 0;
    111
    112	if (phy->flags & ULPI_IC_AUTORESUME)
    113		flags |= ULPI_IFC_CTRL_AUTORESUME;
    114
    115	if (phy->flags & ULPI_IC_EXTVBUS_INDINV)
    116		flags |= ULPI_IFC_CTRL_EXTERNAL_VBUS;
    117
    118	if (phy->flags & ULPI_IC_IND_PASSTHRU)
    119		flags |= ULPI_IFC_CTRL_PASSTHRU;
    120
    121	if (phy->flags & ULPI_IC_PROTECT_DIS)
    122		flags |= ULPI_IFC_CTRL_PROTECT_IFC_DISABLE;
    123
    124	return usb_phy_io_write(phy, flags, ULPI_IFC_CTRL);
    125}
    126
    127static int ulpi_set_flags(struct usb_phy *phy)
    128{
    129	int ret;
    130
    131	ret = ulpi_set_otg_flags(phy);
    132	if (ret)
    133		return ret;
    134
    135	ret = ulpi_set_ic_flags(phy);
    136	if (ret)
    137		return ret;
    138
    139	return ulpi_set_fc_flags(phy);
    140}
    141
    142static int ulpi_check_integrity(struct usb_phy *phy)
    143{
    144	int ret, i;
    145	unsigned int val = 0x55;
    146
    147	for (i = 0; i < 2; i++) {
    148		ret = usb_phy_io_write(phy, val, ULPI_SCRATCH);
    149		if (ret < 0)
    150			return ret;
    151
    152		ret = usb_phy_io_read(phy, ULPI_SCRATCH);
    153		if (ret < 0)
    154			return ret;
    155
    156		if (ret != val) {
    157			pr_err("ULPI integrity check: failed!");
    158			return -ENODEV;
    159		}
    160		val = val << 1;
    161	}
    162
    163	pr_info("ULPI integrity check: passed.\n");
    164
    165	return 0;
    166}
    167
    168static int ulpi_init(struct usb_phy *phy)
    169{
    170	int i, vid, pid, ret;
    171	u32 ulpi_id = 0;
    172
    173	for (i = 0; i < 4; i++) {
    174		ret = usb_phy_io_read(phy, ULPI_PRODUCT_ID_HIGH - i);
    175		if (ret < 0)
    176			return ret;
    177		ulpi_id = (ulpi_id << 8) | ret;
    178	}
    179	vid = ulpi_id & 0xffff;
    180	pid = ulpi_id >> 16;
    181
    182	pr_info("ULPI transceiver vendor/product ID 0x%04x/0x%04x\n", vid, pid);
    183
    184	for (i = 0; i < ARRAY_SIZE(ulpi_ids); i++) {
    185		if (ulpi_ids[i].id == ULPI_ID(vid, pid)) {
    186			pr_info("Found %s ULPI transceiver.\n",
    187				ulpi_ids[i].name);
    188			break;
    189		}
    190	}
    191
    192	ret = ulpi_check_integrity(phy);
    193	if (ret)
    194		return ret;
    195
    196	return ulpi_set_flags(phy);
    197}
    198
    199static int ulpi_set_host(struct usb_otg *otg, struct usb_bus *host)
    200{
    201	struct usb_phy *phy = otg->usb_phy;
    202	unsigned int flags = usb_phy_io_read(phy, ULPI_IFC_CTRL);
    203
    204	if (!host) {
    205		otg->host = NULL;
    206		return 0;
    207	}
    208
    209	otg->host = host;
    210
    211	flags &= ~(ULPI_IFC_CTRL_6_PIN_SERIAL_MODE |
    212		   ULPI_IFC_CTRL_3_PIN_SERIAL_MODE |
    213		   ULPI_IFC_CTRL_CARKITMODE);
    214
    215	if (phy->flags & ULPI_IC_6PIN_SERIAL)
    216		flags |= ULPI_IFC_CTRL_6_PIN_SERIAL_MODE;
    217	else if (phy->flags & ULPI_IC_3PIN_SERIAL)
    218		flags |= ULPI_IFC_CTRL_3_PIN_SERIAL_MODE;
    219	else if (phy->flags & ULPI_IC_CARKIT)
    220		flags |= ULPI_IFC_CTRL_CARKITMODE;
    221
    222	return usb_phy_io_write(phy, flags, ULPI_IFC_CTRL);
    223}
    224
    225static int ulpi_set_vbus(struct usb_otg *otg, bool on)
    226{
    227	struct usb_phy *phy = otg->usb_phy;
    228	unsigned int flags = usb_phy_io_read(phy, ULPI_OTG_CTRL);
    229
    230	flags &= ~(ULPI_OTG_CTRL_DRVVBUS | ULPI_OTG_CTRL_DRVVBUS_EXT);
    231
    232	if (on) {
    233		if (phy->flags & ULPI_OTG_DRVVBUS)
    234			flags |= ULPI_OTG_CTRL_DRVVBUS;
    235
    236		if (phy->flags & ULPI_OTG_DRVVBUS_EXT)
    237			flags |= ULPI_OTG_CTRL_DRVVBUS_EXT;
    238	}
    239
    240	return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL);
    241}
    242
    243static void otg_ulpi_init(struct usb_phy *phy, struct usb_otg *otg,
    244			  struct usb_phy_io_ops *ops,
    245			  unsigned int flags)
    246{
    247	phy->label	= "ULPI";
    248	phy->flags	= flags;
    249	phy->io_ops	= ops;
    250	phy->otg	= otg;
    251	phy->init	= ulpi_init;
    252
    253	otg->usb_phy	= phy;
    254	otg->set_host	= ulpi_set_host;
    255	otg->set_vbus	= ulpi_set_vbus;
    256}
    257
    258struct usb_phy *
    259otg_ulpi_create(struct usb_phy_io_ops *ops,
    260		unsigned int flags)
    261{
    262	struct usb_phy *phy;
    263	struct usb_otg *otg;
    264
    265	phy = kzalloc(sizeof(*phy), GFP_KERNEL);
    266	if (!phy)
    267		return NULL;
    268
    269	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
    270	if (!otg) {
    271		kfree(phy);
    272		return NULL;
    273	}
    274
    275	otg_ulpi_init(phy, otg, ops, flags);
    276
    277	return phy;
    278}
    279EXPORT_SYMBOL_GPL(otg_ulpi_create);
    280
    281struct usb_phy *
    282devm_otg_ulpi_create(struct device *dev,
    283		     struct usb_phy_io_ops *ops,
    284		     unsigned int flags)
    285{
    286	struct usb_phy *phy;
    287	struct usb_otg *otg;
    288
    289	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
    290	if (!phy)
    291		return NULL;
    292
    293	otg = devm_kzalloc(dev, sizeof(*otg), GFP_KERNEL);
    294	if (!otg) {
    295		devm_kfree(dev, phy);
    296		return NULL;
    297	}
    298
    299	otg_ulpi_init(phy, otg, ops, flags);
    300
    301	return phy;
    302}
    303EXPORT_SYMBOL_GPL(devm_otg_ulpi_create);