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-ingenic-usb.c (11096B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Ingenic SoCs USB PHY driver
      4 * Copyright (c) Paul Cercueil <paul@crapouillou.net>
      5 * Copyright (c) 漆鹏振 (Qi Pengzhen) <aric.pzqi@ingenic.com>
      6 * Copyright (c) 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
      7 */
      8
      9#include <linux/bitfield.h>
     10#include <linux/clk.h>
     11#include <linux/delay.h>
     12#include <linux/io.h>
     13#include <linux/module.h>
     14#include <linux/phy/phy.h>
     15#include <linux/platform_device.h>
     16#include <linux/regulator/consumer.h>
     17
     18/* OTGPHY register offsets */
     19#define REG_USBPCR_OFFSET			0x00
     20#define REG_USBRDT_OFFSET			0x04
     21#define REG_USBVBFIL_OFFSET			0x08
     22#define REG_USBPCR1_OFFSET			0x0c
     23
     24/* bits within the USBPCR register */
     25#define USBPCR_USB_MODE				BIT(31)
     26#define USBPCR_AVLD_REG				BIT(30)
     27#define USBPCR_COMMONONN			BIT(25)
     28#define USBPCR_VBUSVLDEXT			BIT(24)
     29#define USBPCR_VBUSVLDEXTSEL		BIT(23)
     30#define USBPCR_POR					BIT(22)
     31#define USBPCR_SIDDQ				BIT(21)
     32#define USBPCR_OTG_DISABLE			BIT(20)
     33#define USBPCR_TXPREEMPHTUNE		BIT(6)
     34
     35#define USBPCR_IDPULLUP_MASK		GENMASK(29, 28)
     36#define USBPCR_IDPULLUP_ALWAYS		0x2
     37#define USBPCR_IDPULLUP_SUSPEND		0x1
     38#define USBPCR_IDPULLUP_OTG			0x0
     39
     40#define USBPCR_COMPDISTUNE_MASK		GENMASK(19, 17)
     41#define USBPCR_COMPDISTUNE_DFT		0x4
     42
     43#define USBPCR_OTGTUNE_MASK			GENMASK(16, 14)
     44#define USBPCR_OTGTUNE_DFT			0x4
     45
     46#define USBPCR_SQRXTUNE_MASK		GENMASK(13, 11)
     47#define USBPCR_SQRXTUNE_DCR_20PCT	0x7
     48#define USBPCR_SQRXTUNE_DFT			0x3
     49
     50#define USBPCR_TXFSLSTUNE_MASK		GENMASK(10, 7)
     51#define USBPCR_TXFSLSTUNE_DCR_50PPT	0xf
     52#define USBPCR_TXFSLSTUNE_DCR_25PPT	0x7
     53#define USBPCR_TXFSLSTUNE_DFT		0x3
     54#define USBPCR_TXFSLSTUNE_INC_25PPT	0x1
     55#define USBPCR_TXFSLSTUNE_INC_50PPT	0x0
     56
     57#define USBPCR_TXHSXVTUNE_MASK		GENMASK(5, 4)
     58#define USBPCR_TXHSXVTUNE_DFT		0x3
     59#define USBPCR_TXHSXVTUNE_DCR_15MV	0x1
     60
     61#define USBPCR_TXRISETUNE_MASK		GENMASK(5, 4)
     62#define USBPCR_TXRISETUNE_DFT		0x3
     63
     64#define USBPCR_TXVREFTUNE_MASK		GENMASK(3, 0)
     65#define USBPCR_TXVREFTUNE_INC_75PPT	0xb
     66#define USBPCR_TXVREFTUNE_INC_25PPT	0x7
     67#define USBPCR_TXVREFTUNE_DFT		0x5
     68
     69/* bits within the USBRDTR register */
     70#define USBRDT_UTMI_RST				BIT(27)
     71#define USBRDT_HB_MASK				BIT(26)
     72#define USBRDT_VBFIL_LD_EN			BIT(25)
     73#define USBRDT_IDDIG_EN				BIT(24)
     74#define USBRDT_IDDIG_REG			BIT(23)
     75#define USBRDT_VBFIL_EN				BIT(2)
     76
     77/* bits within the USBPCR1 register */
     78#define USBPCR1_BVLD_REG			BIT(31)
     79#define USBPCR1_DPPD				BIT(29)
     80#define USBPCR1_DMPD				BIT(28)
     81#define USBPCR1_USB_SEL				BIT(28)
     82#define USBPCR1_PORT_RST			BIT(21)
     83#define USBPCR1_WORD_IF_16BIT		BIT(19)
     84
     85struct ingenic_soc_info {
     86	void (*usb_phy_init)(struct phy *phy);
     87};
     88
     89struct ingenic_usb_phy {
     90	const struct ingenic_soc_info *soc_info;
     91
     92	struct phy *phy;
     93	void __iomem *base;
     94	struct clk *clk;
     95	struct regulator *vcc_supply;
     96};
     97
     98static int ingenic_usb_phy_init(struct phy *phy)
     99{
    100	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
    101	int err;
    102	u32 reg;
    103
    104	err = clk_prepare_enable(priv->clk);
    105	if (err) {
    106		dev_err(&phy->dev, "Unable to start clock: %d\n", err);
    107		return err;
    108	}
    109
    110	priv->soc_info->usb_phy_init(phy);
    111
    112	/* Wait for PHY to reset */
    113	usleep_range(30, 300);
    114	reg = readl(priv->base + REG_USBPCR_OFFSET);
    115	writel(reg & ~USBPCR_POR, priv->base + REG_USBPCR_OFFSET);
    116	usleep_range(300, 1000);
    117
    118	return 0;
    119}
    120
    121static int ingenic_usb_phy_exit(struct phy *phy)
    122{
    123	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
    124
    125	clk_disable_unprepare(priv->clk);
    126	regulator_disable(priv->vcc_supply);
    127
    128	return 0;
    129}
    130
    131static int ingenic_usb_phy_power_on(struct phy *phy)
    132{
    133	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
    134	int err;
    135
    136	err = regulator_enable(priv->vcc_supply);
    137	if (err) {
    138		dev_err(&phy->dev, "Unable to enable VCC: %d\n", err);
    139		return err;
    140	}
    141
    142	return 0;
    143}
    144
    145static int ingenic_usb_phy_power_off(struct phy *phy)
    146{
    147	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
    148
    149	regulator_disable(priv->vcc_supply);
    150
    151	return 0;
    152}
    153
    154static int ingenic_usb_phy_set_mode(struct phy *phy,
    155				  enum phy_mode mode, int submode)
    156{
    157	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
    158	u32 reg;
    159
    160	switch (mode) {
    161	case PHY_MODE_USB_HOST:
    162		reg = readl(priv->base + REG_USBPCR_OFFSET);
    163		u32p_replace_bits(&reg, 1, USBPCR_USB_MODE);
    164		u32p_replace_bits(&reg, 0, USBPCR_VBUSVLDEXT);
    165		u32p_replace_bits(&reg, 0, USBPCR_VBUSVLDEXTSEL);
    166		u32p_replace_bits(&reg, 0, USBPCR_OTG_DISABLE);
    167		writel(reg, priv->base + REG_USBPCR_OFFSET);
    168
    169		break;
    170	case PHY_MODE_USB_DEVICE:
    171		reg = readl(priv->base + REG_USBPCR_OFFSET);
    172		u32p_replace_bits(&reg, 0, USBPCR_USB_MODE);
    173		u32p_replace_bits(&reg, 1, USBPCR_VBUSVLDEXT);
    174		u32p_replace_bits(&reg, 1, USBPCR_VBUSVLDEXTSEL);
    175		u32p_replace_bits(&reg, 1, USBPCR_OTG_DISABLE);
    176		writel(reg, priv->base + REG_USBPCR_OFFSET);
    177
    178		break;
    179	case PHY_MODE_USB_OTG:
    180		reg = readl(priv->base + REG_USBPCR_OFFSET);
    181		u32p_replace_bits(&reg, 1, USBPCR_USB_MODE);
    182		u32p_replace_bits(&reg, 1, USBPCR_VBUSVLDEXT);
    183		u32p_replace_bits(&reg, 1, USBPCR_VBUSVLDEXTSEL);
    184		u32p_replace_bits(&reg, 0, USBPCR_OTG_DISABLE);
    185		writel(reg, priv->base + REG_USBPCR_OFFSET);
    186
    187		break;
    188	default:
    189		return -EINVAL;
    190	}
    191
    192	return 0;
    193}
    194
    195static const struct phy_ops ingenic_usb_phy_ops = {
    196	.init		= ingenic_usb_phy_init,
    197	.exit		= ingenic_usb_phy_exit,
    198	.power_on	= ingenic_usb_phy_power_on,
    199	.power_off	= ingenic_usb_phy_power_off,
    200	.set_mode	= ingenic_usb_phy_set_mode,
    201	.owner		= THIS_MODULE,
    202};
    203
    204static void jz4770_usb_phy_init(struct phy *phy)
    205{
    206	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
    207	u32 reg;
    208
    209	reg = USBPCR_AVLD_REG | USBPCR_COMMONONN | USBPCR_POR |
    210		FIELD_PREP(USBPCR_IDPULLUP_MASK, USBPCR_IDPULLUP_ALWAYS) |
    211		FIELD_PREP(USBPCR_COMPDISTUNE_MASK, USBPCR_COMPDISTUNE_DFT) |
    212		FIELD_PREP(USBPCR_OTGTUNE_MASK, USBPCR_OTGTUNE_DFT) |
    213		FIELD_PREP(USBPCR_SQRXTUNE_MASK, USBPCR_SQRXTUNE_DFT) |
    214		FIELD_PREP(USBPCR_TXFSLSTUNE_MASK, USBPCR_TXFSLSTUNE_DFT) |
    215		FIELD_PREP(USBPCR_TXRISETUNE_MASK, USBPCR_TXRISETUNE_DFT) |
    216		FIELD_PREP(USBPCR_TXVREFTUNE_MASK, USBPCR_TXVREFTUNE_DFT);
    217	writel(reg, priv->base + REG_USBPCR_OFFSET);
    218}
    219
    220static void jz4775_usb_phy_init(struct phy *phy)
    221{
    222	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
    223	u32 reg;
    224
    225	reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_USB_SEL |
    226		USBPCR1_WORD_IF_16BIT;
    227	writel(reg, priv->base + REG_USBPCR1_OFFSET);
    228
    229	reg = USBPCR_COMMONONN | USBPCR_POR |
    230		FIELD_PREP(USBPCR_TXVREFTUNE_MASK, USBPCR_TXVREFTUNE_INC_75PPT);
    231	writel(reg, priv->base + REG_USBPCR_OFFSET);
    232}
    233
    234static void jz4780_usb_phy_init(struct phy *phy)
    235{
    236	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
    237	u32 reg;
    238
    239	reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_USB_SEL |
    240		USBPCR1_WORD_IF_16BIT;
    241	writel(reg, priv->base + REG_USBPCR1_OFFSET);
    242
    243	reg = USBPCR_TXPREEMPHTUNE | USBPCR_COMMONONN | USBPCR_POR;
    244	writel(reg, priv->base + REG_USBPCR_OFFSET);
    245}
    246
    247static void x1000_usb_phy_init(struct phy *phy)
    248{
    249	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
    250	u32 reg;
    251
    252	reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_WORD_IF_16BIT;
    253	writel(reg, priv->base + REG_USBPCR1_OFFSET);
    254
    255	reg = USBPCR_TXPREEMPHTUNE | USBPCR_COMMONONN | USBPCR_POR |
    256		FIELD_PREP(USBPCR_SQRXTUNE_MASK, USBPCR_SQRXTUNE_DCR_20PCT) |
    257		FIELD_PREP(USBPCR_TXHSXVTUNE_MASK, USBPCR_TXHSXVTUNE_DCR_15MV) |
    258		FIELD_PREP(USBPCR_TXVREFTUNE_MASK, USBPCR_TXVREFTUNE_INC_25PPT);
    259	writel(reg, priv->base + REG_USBPCR_OFFSET);
    260}
    261
    262static void x1830_usb_phy_init(struct phy *phy)
    263{
    264	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
    265	u32 reg;
    266
    267	/* rdt */
    268	writel(USBRDT_VBFIL_EN | USBRDT_UTMI_RST, priv->base + REG_USBRDT_OFFSET);
    269
    270	reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_WORD_IF_16BIT |
    271		USBPCR1_DMPD | USBPCR1_DPPD;
    272	writel(reg, priv->base + REG_USBPCR1_OFFSET);
    273
    274	reg = USBPCR_VBUSVLDEXT | USBPCR_TXPREEMPHTUNE | USBPCR_COMMONONN | USBPCR_POR |
    275		FIELD_PREP(USBPCR_IDPULLUP_MASK, USBPCR_IDPULLUP_OTG);
    276	writel(reg, priv->base + REG_USBPCR_OFFSET);
    277}
    278
    279static void x2000_usb_phy_init(struct phy *phy)
    280{
    281	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
    282	u32 reg;
    283
    284	reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_DPPD | USBPCR1_DMPD;
    285	writel(reg & ~USBPCR1_PORT_RST, priv->base + REG_USBPCR1_OFFSET);
    286
    287	reg = USBPCR_POR | FIELD_PREP(USBPCR_IDPULLUP_MASK, USBPCR_IDPULLUP_OTG);
    288	writel(reg, priv->base + REG_USBPCR_OFFSET);
    289}
    290
    291static const struct ingenic_soc_info jz4770_soc_info = {
    292	.usb_phy_init = jz4770_usb_phy_init,
    293};
    294
    295static const struct ingenic_soc_info jz4775_soc_info = {
    296	.usb_phy_init = jz4775_usb_phy_init,
    297};
    298
    299static const struct ingenic_soc_info jz4780_soc_info = {
    300	.usb_phy_init = jz4780_usb_phy_init,
    301};
    302
    303static const struct ingenic_soc_info x1000_soc_info = {
    304	.usb_phy_init = x1000_usb_phy_init,
    305};
    306
    307static const struct ingenic_soc_info x1830_soc_info = {
    308	.usb_phy_init = x1830_usb_phy_init,
    309};
    310
    311static const struct ingenic_soc_info x2000_soc_info = {
    312	.usb_phy_init = x2000_usb_phy_init,
    313};
    314
    315static int ingenic_usb_phy_probe(struct platform_device *pdev)
    316{
    317	struct ingenic_usb_phy *priv;
    318	struct phy_provider *provider;
    319	struct device *dev = &pdev->dev;
    320	int err;
    321
    322	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
    323	if (!priv)
    324		return -ENOMEM;
    325
    326	priv->soc_info = device_get_match_data(dev);
    327	if (!priv->soc_info) {
    328		dev_err(dev, "Error: No device match found\n");
    329		return -ENODEV;
    330	}
    331
    332	priv->base = devm_platform_ioremap_resource(pdev, 0);
    333	if (IS_ERR(priv->base)) {
    334		dev_err(dev, "Failed to map registers\n");
    335		return PTR_ERR(priv->base);
    336	}
    337
    338	priv->clk = devm_clk_get(dev, NULL);
    339	if (IS_ERR(priv->clk)) {
    340		err = PTR_ERR(priv->clk);
    341		if (err != -EPROBE_DEFER)
    342			dev_err(dev, "Failed to get clock\n");
    343		return err;
    344	}
    345
    346	priv->vcc_supply = devm_regulator_get(dev, "vcc");
    347	if (IS_ERR(priv->vcc_supply)) {
    348		err = PTR_ERR(priv->vcc_supply);
    349		if (err != -EPROBE_DEFER)
    350			dev_err(dev, "Failed to get regulator\n");
    351		return err;
    352	}
    353
    354	priv->phy = devm_phy_create(dev, NULL, &ingenic_usb_phy_ops);
    355	if (IS_ERR(priv->phy))
    356		return PTR_ERR(priv->phy);
    357
    358	phy_set_drvdata(priv->phy, priv);
    359
    360	provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
    361
    362	return PTR_ERR_OR_ZERO(provider);
    363}
    364
    365static const struct of_device_id ingenic_usb_phy_of_matches[] = {
    366	{ .compatible = "ingenic,jz4770-phy", .data = &jz4770_soc_info },
    367	{ .compatible = "ingenic,jz4775-phy", .data = &jz4775_soc_info },
    368	{ .compatible = "ingenic,jz4780-phy", .data = &jz4780_soc_info },
    369	{ .compatible = "ingenic,x1000-phy", .data = &x1000_soc_info },
    370	{ .compatible = "ingenic,x1830-phy", .data = &x1830_soc_info },
    371	{ .compatible = "ingenic,x2000-phy", .data = &x2000_soc_info },
    372	{ /* sentinel */ }
    373};
    374MODULE_DEVICE_TABLE(of, ingenic_usb_phy_of_matches);
    375
    376static struct platform_driver ingenic_usb_phy_driver = {
    377	.probe		= ingenic_usb_phy_probe,
    378	.driver		= {
    379		.name	= "ingenic-usb-phy",
    380		.of_match_table = ingenic_usb_phy_of_matches,
    381	},
    382};
    383module_platform_driver(ingenic_usb_phy_driver);
    384
    385MODULE_AUTHOR("周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>");
    386MODULE_AUTHOR("漆鹏振 (Qi Pengzhen) <aric.pzqi@ingenic.com>");
    387MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
    388MODULE_DESCRIPTION("Ingenic SoCs USB PHY driver");
    389MODULE_LICENSE("GPL");