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-pxa-28nm-hsic.c (5360B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2015 Linaro, Ltd.
      4 * Rob Herring <robh@kernel.org>
      5 *
      6 * Based on vendor driver:
      7 * Copyright (C) 2013 Marvell Inc.
      8 * Author: Chao Xie <xiechao.mail@gmail.com>
      9 */
     10
     11#include <linux/delay.h>
     12#include <linux/slab.h>
     13#include <linux/of.h>
     14#include <linux/io.h>
     15#include <linux/iopoll.h>
     16#include <linux/err.h>
     17#include <linux/clk.h>
     18#include <linux/module.h>
     19#include <linux/platform_device.h>
     20#include <linux/phy/phy.h>
     21
     22#define PHY_28NM_HSIC_CTRL			0x08
     23#define PHY_28NM_HSIC_IMPCAL_CAL		0x18
     24#define PHY_28NM_HSIC_PLL_CTRL01		0x1c
     25#define PHY_28NM_HSIC_PLL_CTRL2			0x20
     26#define PHY_28NM_HSIC_INT			0x28
     27
     28#define PHY_28NM_HSIC_PLL_SELLPFR_SHIFT		26
     29#define PHY_28NM_HSIC_PLL_FBDIV_SHIFT		0
     30#define PHY_28NM_HSIC_PLL_REFDIV_SHIFT		9
     31
     32#define PHY_28NM_HSIC_S2H_PU_PLL		BIT(10)
     33#define PHY_28NM_HSIC_H2S_PLL_LOCK		BIT(15)
     34#define PHY_28NM_HSIC_S2H_HSIC_EN		BIT(7)
     35#define S2H_DRV_SE0_4RESUME			BIT(14)
     36#define PHY_28NM_HSIC_H2S_IMPCAL_DONE		BIT(27)
     37
     38#define PHY_28NM_HSIC_CONNECT_INT		BIT(1)
     39#define PHY_28NM_HSIC_HS_READY_INT		BIT(2)
     40
     41struct mv_hsic_phy {
     42	struct phy		*phy;
     43	struct platform_device	*pdev;
     44	void __iomem		*base;
     45	struct clk		*clk;
     46};
     47
     48static int wait_for_reg(void __iomem *reg, u32 mask, u32 ms)
     49{
     50	u32 val;
     51
     52	return readl_poll_timeout(reg, val, ((val & mask) == mask),
     53				  1000, 1000 * ms);
     54}
     55
     56static int mv_hsic_phy_init(struct phy *phy)
     57{
     58	struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy);
     59	struct platform_device *pdev = mv_phy->pdev;
     60	void __iomem *base = mv_phy->base;
     61	int ret;
     62
     63	clk_prepare_enable(mv_phy->clk);
     64
     65	/* Set reference clock */
     66	writel(0x1 << PHY_28NM_HSIC_PLL_SELLPFR_SHIFT |
     67		0xf0 << PHY_28NM_HSIC_PLL_FBDIV_SHIFT |
     68		0xd << PHY_28NM_HSIC_PLL_REFDIV_SHIFT,
     69		base + PHY_28NM_HSIC_PLL_CTRL01);
     70
     71	/* Turn on PLL */
     72	writel(readl(base + PHY_28NM_HSIC_PLL_CTRL2) |
     73		PHY_28NM_HSIC_S2H_PU_PLL,
     74		base + PHY_28NM_HSIC_PLL_CTRL2);
     75
     76	/* Make sure PHY PLL is locked */
     77	ret = wait_for_reg(base + PHY_28NM_HSIC_PLL_CTRL2,
     78			   PHY_28NM_HSIC_H2S_PLL_LOCK, 100);
     79	if (ret) {
     80		dev_err(&pdev->dev, "HSIC PHY PLL not locked after 100mS.");
     81		clk_disable_unprepare(mv_phy->clk);
     82	}
     83
     84	return ret;
     85}
     86
     87static int mv_hsic_phy_power_on(struct phy *phy)
     88{
     89	struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy);
     90	struct platform_device *pdev = mv_phy->pdev;
     91	void __iomem *base = mv_phy->base;
     92	u32 reg;
     93	int ret;
     94
     95	reg = readl(base + PHY_28NM_HSIC_CTRL);
     96	/* Avoid SE0 state when resume for some device will take it as reset */
     97	reg &= ~S2H_DRV_SE0_4RESUME;
     98	reg |= PHY_28NM_HSIC_S2H_HSIC_EN;	/* Enable HSIC PHY */
     99	writel(reg, base + PHY_28NM_HSIC_CTRL);
    100
    101	/*
    102	 *  Calibration Timing
    103	 *		   ____________________________
    104	 *  CAL START   ___|
    105	 *			   ____________________
    106	 *  CAL_DONE    ___________|
    107	 *		   | 400us |
    108	 */
    109
    110	/* Make sure PHY Calibration is ready */
    111	ret = wait_for_reg(base + PHY_28NM_HSIC_IMPCAL_CAL,
    112			   PHY_28NM_HSIC_H2S_IMPCAL_DONE, 100);
    113	if (ret) {
    114		dev_warn(&pdev->dev, "HSIC PHY READY not set after 100mS.");
    115		return ret;
    116	}
    117
    118	/* Waiting for HSIC connect int*/
    119	ret = wait_for_reg(base + PHY_28NM_HSIC_INT,
    120			   PHY_28NM_HSIC_CONNECT_INT, 200);
    121	if (ret)
    122		dev_warn(&pdev->dev, "HSIC wait for connect interrupt timeout.");
    123
    124	return ret;
    125}
    126
    127static int mv_hsic_phy_power_off(struct phy *phy)
    128{
    129	struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy);
    130	void __iomem *base = mv_phy->base;
    131
    132	writel(readl(base + PHY_28NM_HSIC_CTRL) & ~PHY_28NM_HSIC_S2H_HSIC_EN,
    133		base + PHY_28NM_HSIC_CTRL);
    134
    135	return 0;
    136}
    137
    138static int mv_hsic_phy_exit(struct phy *phy)
    139{
    140	struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy);
    141	void __iomem *base = mv_phy->base;
    142
    143	/* Turn off PLL */
    144	writel(readl(base + PHY_28NM_HSIC_PLL_CTRL2) &
    145		~PHY_28NM_HSIC_S2H_PU_PLL,
    146		base + PHY_28NM_HSIC_PLL_CTRL2);
    147
    148	clk_disable_unprepare(mv_phy->clk);
    149	return 0;
    150}
    151
    152
    153static const struct phy_ops hsic_ops = {
    154	.init		= mv_hsic_phy_init,
    155	.power_on	= mv_hsic_phy_power_on,
    156	.power_off	= mv_hsic_phy_power_off,
    157	.exit		= mv_hsic_phy_exit,
    158	.owner		= THIS_MODULE,
    159};
    160
    161static int mv_hsic_phy_probe(struct platform_device *pdev)
    162{
    163	struct phy_provider *phy_provider;
    164	struct mv_hsic_phy *mv_phy;
    165
    166	mv_phy = devm_kzalloc(&pdev->dev, sizeof(*mv_phy), GFP_KERNEL);
    167	if (!mv_phy)
    168		return -ENOMEM;
    169
    170	mv_phy->pdev = pdev;
    171
    172	mv_phy->clk = devm_clk_get(&pdev->dev, NULL);
    173	if (IS_ERR(mv_phy->clk)) {
    174		dev_err(&pdev->dev, "failed to get clock.\n");
    175		return PTR_ERR(mv_phy->clk);
    176	}
    177
    178	mv_phy->base = devm_platform_ioremap_resource(pdev, 0);
    179	if (IS_ERR(mv_phy->base))
    180		return PTR_ERR(mv_phy->base);
    181
    182	mv_phy->phy = devm_phy_create(&pdev->dev, pdev->dev.of_node, &hsic_ops);
    183	if (IS_ERR(mv_phy->phy))
    184		return PTR_ERR(mv_phy->phy);
    185
    186	phy_set_drvdata(mv_phy->phy, mv_phy);
    187
    188	phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
    189	return PTR_ERR_OR_ZERO(phy_provider);
    190}
    191
    192static const struct of_device_id mv_hsic_phy_dt_match[] = {
    193	{ .compatible = "marvell,pxa1928-hsic-phy", },
    194	{},
    195};
    196MODULE_DEVICE_TABLE(of, mv_hsic_phy_dt_match);
    197
    198static struct platform_driver mv_hsic_phy_driver = {
    199	.probe	= mv_hsic_phy_probe,
    200	.driver = {
    201		.name   = "mv-hsic-phy",
    202		.of_match_table = of_match_ptr(mv_hsic_phy_dt_match),
    203	},
    204};
    205module_platform_driver(mv_hsic_phy_driver);
    206
    207MODULE_AUTHOR("Rob Herring <robh@kernel.org>");
    208MODULE_DESCRIPTION("Marvell HSIC phy driver");
    209MODULE_LICENSE("GPL v2");