1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2019 Daniel Golle <daniel@makrotopia.org>
7 #include <dt-bindings/phy/phy.h>
9 #include <linux/iopoll.h>
10 #include <linux/module.h>
11 #include <linux/of_address.h>
12 #include <linux/of_device.h>
13 #include <linux/mfd/syscon.h>
14 #include <linux/phy/phy.h>
15 #include <linux/platform_device.h>
16 #include <linux/regmap.h>
17 #include <linux/reset.h>
19 #define ADDR_VAL(val) ((val) & 0xFFFF)
20 #define DATA_VAL(val) ((val) & 0xFFFF)
22 #define SYS_CTRL_HCSL_CTRL_REGOFFSET 0x114
25 HCSL_BIAS_ON
= BIT(0),
26 HCSL_PCIE_EN
= BIT(1),
27 HCSL_PCIEA_EN
= BIT(2),
28 HCSL_PCIEB_EN
= BIT(3),
32 /* pcie phy reg offset */
35 /* phy data reg bits */
41 struct oxnas_pcie_phy
{
43 void __iomem
*membase
;
44 const struct phy_ops
*ops
;
45 struct regmap
*sys_ctrl
;
46 struct reset_control
*rstc
;
49 static int oxnas_pcie_phy_init(struct phy
*phy
)
51 struct oxnas_pcie_phy
*pciephy
= phy_get_drvdata(phy
);
54 /* generate clocks from HCSL buffers, shared parts */
55 regmap_write(pciephy
->sys_ctrl
, SYS_CTRL_HCSL_CTRL_REGOFFSET
, HCSL_BIAS_ON
|HCSL_PCIE_EN
);
57 /* Ensure PCIe PHY is properly reset */
58 ret
= reset_control_reset(pciephy
->rstc
);
61 dev_err(pciephy
->dev
, "phy reset failed %d\n", ret
);
68 static int oxnas_pcie_phy_power_on(struct phy
*phy
)
70 struct oxnas_pcie_phy
*pciephy
= phy_get_drvdata(phy
);
72 /* Enable PCIe Pre-Emphasis: What these value means? */
73 writel(ADDR_VAL(0x0014), pciephy
->membase
+ PHY_ADDR
);
74 writel(DATA_VAL(0xce10) | CAP_DATA
, pciephy
->membase
+ PHY_DATA
);
75 writel(DATA_VAL(0xce10) | WRITE_EN
, pciephy
->membase
+ PHY_DATA
);
77 writel(ADDR_VAL(0x2004), pciephy
->membase
+ PHY_ADDR
);
78 writel(DATA_VAL(0x82c7) | CAP_DATA
, pciephy
->membase
+ PHY_DATA
);
79 writel(DATA_VAL(0x82c7) | WRITE_EN
, pciephy
->membase
+ PHY_DATA
);
84 static const struct phy_ops ops
= {
85 .init
= oxnas_pcie_phy_init
,
86 .power_on
= oxnas_pcie_phy_power_on
,
90 static int oxnas_pcie_phy_probe(struct platform_device
*pdev
)
92 struct device
*dev
= &pdev
->dev
;
93 struct device_node
*np
= pdev
->dev
.of_node
;
94 struct phy
*generic_phy
;
95 struct phy_provider
*phy_provider
;
96 struct oxnas_pcie_phy
*pciephy
;
97 struct regmap
*sys_ctrl
;
98 struct reset_control
*rstc
;
99 void __iomem
*membase
;
101 membase
= of_iomap(np
, 0);
103 return PTR_ERR(membase
);
105 sys_ctrl
= syscon_regmap_lookup_by_compatible("oxsemi,ox820-sys-ctrl");
106 if (IS_ERR(sys_ctrl
))
107 return PTR_ERR(sys_ctrl
);
109 rstc
= devm_reset_control_get_shared(dev
, "phy");
111 return PTR_ERR(rstc
);
113 pciephy
= devm_kzalloc(dev
, sizeof(*pciephy
), GFP_KERNEL
);
117 pciephy
->sys_ctrl
= sys_ctrl
;
118 pciephy
->rstc
= rstc
;
119 pciephy
->membase
= membase
;
123 generic_phy
= devm_phy_create(dev
, dev
->of_node
, pciephy
->ops
);
124 if (IS_ERR(generic_phy
)) {
125 dev_err(dev
, "failed to create PHY\n");
126 return PTR_ERR(generic_phy
);
129 phy_set_drvdata(generic_phy
, pciephy
);
130 phy_provider
= devm_of_phy_provider_register(dev
, of_phy_simple_xlate
);
132 return PTR_ERR_OR_ZERO(phy_provider
);
135 static const struct of_device_id oxnas_pcie_phy_id_table
[] = {
136 { .compatible
= "oxsemi,ox820-pcie-phy" },
140 static struct platform_driver oxnas_pcie_phy_driver
= {
141 .probe
= oxnas_pcie_phy_probe
,
143 .name
= "ox820-pcie-phy",
144 .of_match_table
= oxnas_pcie_phy_id_table
,
148 builtin_platform_driver(oxnas_pcie_phy_driver
);