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

mdio-mux-meson-g12a.c (9288B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* Copyright (c) 2019 Baylibre, SAS.
      3 * Author: Jerome Brunet <jbrunet@baylibre.com>
      4 */
      5
      6#include <linux/bitfield.h>
      7#include <linux/clk.h>
      8#include <linux/clk-provider.h>
      9#include <linux/device.h>
     10#include <linux/io.h>
     11#include <linux/iopoll.h>
     12#include <linux/mdio-mux.h>
     13#include <linux/module.h>
     14#include <linux/phy.h>
     15#include <linux/platform_device.h>
     16
     17#define ETH_PLL_STS		0x40
     18#define ETH_PLL_CTL0		0x44
     19#define  PLL_CTL0_LOCK_DIG	BIT(30)
     20#define  PLL_CTL0_RST		BIT(29)
     21#define  PLL_CTL0_EN		BIT(28)
     22#define  PLL_CTL0_SEL		BIT(23)
     23#define  PLL_CTL0_N		GENMASK(14, 10)
     24#define  PLL_CTL0_M		GENMASK(8, 0)
     25#define  PLL_LOCK_TIMEOUT	1000000
     26#define  PLL_MUX_NUM_PARENT	2
     27#define ETH_PLL_CTL1		0x48
     28#define ETH_PLL_CTL2		0x4c
     29#define ETH_PLL_CTL3		0x50
     30#define ETH_PLL_CTL4		0x54
     31#define ETH_PLL_CTL5		0x58
     32#define ETH_PLL_CTL6		0x5c
     33#define ETH_PLL_CTL7		0x60
     34
     35#define ETH_PHY_CNTL0		0x80
     36#define   EPHY_G12A_ID		0x33010180
     37#define ETH_PHY_CNTL1		0x84
     38#define  PHY_CNTL1_ST_MODE	GENMASK(2, 0)
     39#define  PHY_CNTL1_ST_PHYADD	GENMASK(7, 3)
     40#define   EPHY_DFLT_ADD		8
     41#define  PHY_CNTL1_MII_MODE	GENMASK(15, 14)
     42#define   EPHY_MODE_RMII	0x1
     43#define  PHY_CNTL1_CLK_EN	BIT(16)
     44#define  PHY_CNTL1_CLKFREQ	BIT(17)
     45#define  PHY_CNTL1_PHY_ENB	BIT(18)
     46#define ETH_PHY_CNTL2		0x88
     47#define  PHY_CNTL2_USE_INTERNAL	BIT(5)
     48#define  PHY_CNTL2_SMI_SRC_MAC	BIT(6)
     49#define  PHY_CNTL2_RX_CLK_EPHY	BIT(9)
     50
     51#define MESON_G12A_MDIO_EXTERNAL_ID 0
     52#define MESON_G12A_MDIO_INTERNAL_ID 1
     53
     54struct g12a_mdio_mux {
     55	bool pll_is_enabled;
     56	void __iomem *regs;
     57	void *mux_handle;
     58	struct clk *pclk;
     59	struct clk *pll;
     60};
     61
     62struct g12a_ephy_pll {
     63	void __iomem *base;
     64	struct clk_hw hw;
     65};
     66
     67#define g12a_ephy_pll_to_dev(_hw)			\
     68	container_of(_hw, struct g12a_ephy_pll, hw)
     69
     70static unsigned long g12a_ephy_pll_recalc_rate(struct clk_hw *hw,
     71					       unsigned long parent_rate)
     72{
     73	struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
     74	u32 val, m, n;
     75
     76	val = readl(pll->base + ETH_PLL_CTL0);
     77	m = FIELD_GET(PLL_CTL0_M, val);
     78	n = FIELD_GET(PLL_CTL0_N, val);
     79
     80	return parent_rate * m / n;
     81}
     82
     83static int g12a_ephy_pll_enable(struct clk_hw *hw)
     84{
     85	struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
     86	u32 val = readl(pll->base + ETH_PLL_CTL0);
     87
     88	/* Apply both enable an reset */
     89	val |= PLL_CTL0_RST | PLL_CTL0_EN;
     90	writel(val, pll->base + ETH_PLL_CTL0);
     91
     92	/* Clear the reset to let PLL lock */
     93	val &= ~PLL_CTL0_RST;
     94	writel(val, pll->base + ETH_PLL_CTL0);
     95
     96	/* Poll on the digital lock instead of the usual analog lock
     97	 * This is done because bit 31 is unreliable on some SoC. Bit
     98	 * 31 may indicate that the PLL is not lock even though the clock
     99	 * is actually running
    100	 */
    101	return readl_poll_timeout(pll->base + ETH_PLL_CTL0, val,
    102				  val & PLL_CTL0_LOCK_DIG, 0, PLL_LOCK_TIMEOUT);
    103}
    104
    105static void g12a_ephy_pll_disable(struct clk_hw *hw)
    106{
    107	struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
    108	u32 val;
    109
    110	val = readl(pll->base + ETH_PLL_CTL0);
    111	val &= ~PLL_CTL0_EN;
    112	val |= PLL_CTL0_RST;
    113	writel(val, pll->base + ETH_PLL_CTL0);
    114}
    115
    116static int g12a_ephy_pll_is_enabled(struct clk_hw *hw)
    117{
    118	struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
    119	unsigned int val;
    120
    121	val = readl(pll->base + ETH_PLL_CTL0);
    122
    123	return (val & PLL_CTL0_LOCK_DIG) ? 1 : 0;
    124}
    125
    126static int g12a_ephy_pll_init(struct clk_hw *hw)
    127{
    128	struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
    129
    130	/* Apply PLL HW settings */
    131	writel(0x29c0040a, pll->base + ETH_PLL_CTL0);
    132	writel(0x927e0000, pll->base + ETH_PLL_CTL1);
    133	writel(0xac5f49e5, pll->base + ETH_PLL_CTL2);
    134	writel(0x00000000, pll->base + ETH_PLL_CTL3);
    135	writel(0x00000000, pll->base + ETH_PLL_CTL4);
    136	writel(0x20200000, pll->base + ETH_PLL_CTL5);
    137	writel(0x0000c002, pll->base + ETH_PLL_CTL6);
    138	writel(0x00000023, pll->base + ETH_PLL_CTL7);
    139
    140	return 0;
    141}
    142
    143static const struct clk_ops g12a_ephy_pll_ops = {
    144	.recalc_rate	= g12a_ephy_pll_recalc_rate,
    145	.is_enabled	= g12a_ephy_pll_is_enabled,
    146	.enable		= g12a_ephy_pll_enable,
    147	.disable	= g12a_ephy_pll_disable,
    148	.init		= g12a_ephy_pll_init,
    149};
    150
    151static int g12a_enable_internal_mdio(struct g12a_mdio_mux *priv)
    152{
    153	int ret;
    154
    155	/* Enable the phy clock */
    156	if (!priv->pll_is_enabled) {
    157		ret = clk_prepare_enable(priv->pll);
    158		if (ret)
    159			return ret;
    160	}
    161
    162	priv->pll_is_enabled = true;
    163
    164	/* Initialize ephy control */
    165	writel(EPHY_G12A_ID, priv->regs + ETH_PHY_CNTL0);
    166	writel(FIELD_PREP(PHY_CNTL1_ST_MODE, 3) |
    167	       FIELD_PREP(PHY_CNTL1_ST_PHYADD, EPHY_DFLT_ADD) |
    168	       FIELD_PREP(PHY_CNTL1_MII_MODE, EPHY_MODE_RMII) |
    169	       PHY_CNTL1_CLK_EN |
    170	       PHY_CNTL1_CLKFREQ |
    171	       PHY_CNTL1_PHY_ENB,
    172	       priv->regs + ETH_PHY_CNTL1);
    173	writel(PHY_CNTL2_USE_INTERNAL |
    174	       PHY_CNTL2_SMI_SRC_MAC |
    175	       PHY_CNTL2_RX_CLK_EPHY,
    176	       priv->regs + ETH_PHY_CNTL2);
    177
    178	return 0;
    179}
    180
    181static int g12a_enable_external_mdio(struct g12a_mdio_mux *priv)
    182{
    183	/* Reset the mdio bus mux */
    184	writel_relaxed(0x0, priv->regs + ETH_PHY_CNTL2);
    185
    186	/* Disable the phy clock if enabled */
    187	if (priv->pll_is_enabled) {
    188		clk_disable_unprepare(priv->pll);
    189		priv->pll_is_enabled = false;
    190	}
    191
    192	return 0;
    193}
    194
    195static int g12a_mdio_switch_fn(int current_child, int desired_child,
    196			       void *data)
    197{
    198	struct g12a_mdio_mux *priv = dev_get_drvdata(data);
    199
    200	if (current_child == desired_child)
    201		return 0;
    202
    203	switch (desired_child) {
    204	case MESON_G12A_MDIO_EXTERNAL_ID:
    205		return g12a_enable_external_mdio(priv);
    206	case MESON_G12A_MDIO_INTERNAL_ID:
    207		return g12a_enable_internal_mdio(priv);
    208	default:
    209		return -EINVAL;
    210	}
    211}
    212
    213static const struct of_device_id g12a_mdio_mux_match[] = {
    214	{ .compatible = "amlogic,g12a-mdio-mux", },
    215	{},
    216};
    217MODULE_DEVICE_TABLE(of, g12a_mdio_mux_match);
    218
    219static int g12a_ephy_glue_clk_register(struct device *dev)
    220{
    221	struct g12a_mdio_mux *priv = dev_get_drvdata(dev);
    222	const char *parent_names[PLL_MUX_NUM_PARENT];
    223	struct clk_init_data init;
    224	struct g12a_ephy_pll *pll;
    225	struct clk_mux *mux;
    226	struct clk *clk;
    227	char *name;
    228	int i;
    229
    230	/* get the mux parents */
    231	for (i = 0; i < PLL_MUX_NUM_PARENT; i++) {
    232		char in_name[8];
    233
    234		snprintf(in_name, sizeof(in_name), "clkin%d", i);
    235		clk = devm_clk_get(dev, in_name);
    236		if (IS_ERR(clk)) {
    237			if (PTR_ERR(clk) != -EPROBE_DEFER)
    238				dev_err(dev, "Missing clock %s\n", in_name);
    239			return PTR_ERR(clk);
    240		}
    241
    242		parent_names[i] = __clk_get_name(clk);
    243	}
    244
    245	/* create the input mux */
    246	mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
    247	if (!mux)
    248		return -ENOMEM;
    249
    250	name = kasprintf(GFP_KERNEL, "%s#mux", dev_name(dev));
    251	if (!name)
    252		return -ENOMEM;
    253
    254	init.name = name;
    255	init.ops = &clk_mux_ro_ops;
    256	init.flags = 0;
    257	init.parent_names = parent_names;
    258	init.num_parents = PLL_MUX_NUM_PARENT;
    259
    260	mux->reg = priv->regs + ETH_PLL_CTL0;
    261	mux->shift = __ffs(PLL_CTL0_SEL);
    262	mux->mask = PLL_CTL0_SEL >> mux->shift;
    263	mux->hw.init = &init;
    264
    265	clk = devm_clk_register(dev, &mux->hw);
    266	kfree(name);
    267	if (IS_ERR(clk)) {
    268		dev_err(dev, "failed to register input mux\n");
    269		return PTR_ERR(clk);
    270	}
    271
    272	/* create the pll */
    273	pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
    274	if (!pll)
    275		return -ENOMEM;
    276
    277	name = kasprintf(GFP_KERNEL, "%s#pll", dev_name(dev));
    278	if (!name)
    279		return -ENOMEM;
    280
    281	init.name = name;
    282	init.ops = &g12a_ephy_pll_ops;
    283	init.flags = 0;
    284	parent_names[0] = __clk_get_name(clk);
    285	init.parent_names = parent_names;
    286	init.num_parents = 1;
    287
    288	pll->base = priv->regs;
    289	pll->hw.init = &init;
    290
    291	clk = devm_clk_register(dev, &pll->hw);
    292	kfree(name);
    293	if (IS_ERR(clk)) {
    294		dev_err(dev, "failed to register input mux\n");
    295		return PTR_ERR(clk);
    296	}
    297
    298	priv->pll = clk;
    299
    300	return 0;
    301}
    302
    303static int g12a_mdio_mux_probe(struct platform_device *pdev)
    304{
    305	struct device *dev = &pdev->dev;
    306	struct g12a_mdio_mux *priv;
    307	int ret;
    308
    309	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
    310	if (!priv)
    311		return -ENOMEM;
    312
    313	platform_set_drvdata(pdev, priv);
    314
    315	priv->regs = devm_platform_ioremap_resource(pdev, 0);
    316	if (IS_ERR(priv->regs))
    317		return PTR_ERR(priv->regs);
    318
    319	priv->pclk = devm_clk_get(dev, "pclk");
    320	if (IS_ERR(priv->pclk)) {
    321		ret = PTR_ERR(priv->pclk);
    322		if (ret != -EPROBE_DEFER)
    323			dev_err(dev, "failed to get peripheral clock\n");
    324		return ret;
    325	}
    326
    327	/* Make sure the device registers are clocked */
    328	ret = clk_prepare_enable(priv->pclk);
    329	if (ret) {
    330		dev_err(dev, "failed to enable peripheral clock");
    331		return ret;
    332	}
    333
    334	/* Register PLL in CCF */
    335	ret = g12a_ephy_glue_clk_register(dev);
    336	if (ret)
    337		goto err;
    338
    339	ret = mdio_mux_init(dev, dev->of_node, g12a_mdio_switch_fn,
    340			    &priv->mux_handle, dev, NULL);
    341	if (ret) {
    342		if (ret != -EPROBE_DEFER)
    343			dev_err(dev, "mdio multiplexer init failed: %d", ret);
    344		goto err;
    345	}
    346
    347	return 0;
    348
    349err:
    350	clk_disable_unprepare(priv->pclk);
    351	return ret;
    352}
    353
    354static int g12a_mdio_mux_remove(struct platform_device *pdev)
    355{
    356	struct g12a_mdio_mux *priv = platform_get_drvdata(pdev);
    357
    358	mdio_mux_uninit(priv->mux_handle);
    359
    360	if (priv->pll_is_enabled)
    361		clk_disable_unprepare(priv->pll);
    362
    363	clk_disable_unprepare(priv->pclk);
    364
    365	return 0;
    366}
    367
    368static struct platform_driver g12a_mdio_mux_driver = {
    369	.probe		= g12a_mdio_mux_probe,
    370	.remove		= g12a_mdio_mux_remove,
    371	.driver		= {
    372		.name	= "g12a-mdio_mux",
    373		.of_match_table = g12a_mdio_mux_match,
    374	},
    375};
    376module_platform_driver(g12a_mdio_mux_driver);
    377
    378MODULE_DESCRIPTION("Amlogic G12a MDIO multiplexer driver");
    379MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
    380MODULE_LICENSE("GPL v2");