1 // SPDX-License-Identifier: GPL-2.0
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
;
48 static int oxnas_pcie_phy_init(struct phy
*phy
)
50 struct oxnas_pcie_phy
*pciephy
= phy_get_drvdata(phy
);
51 struct reset_control
*rstc
;
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 rstc
= reset_control_get(pciephy
->dev
, "phy");
62 ret
= reset_control_reset(rstc
);
63 reset_control_put(rstc
);
67 dev_err(pciephy
->dev
, "phy reset failed %d\n", ret
);
74 static int oxnas_pcie_phy_power_on(struct phy
*phy
)
76 struct oxnas_pcie_phy
*pciephy
= phy_get_drvdata(phy
);
78 /* Enable PCIe Pre-Emphasis: What these value means? */
79 writel(ADDR_VAL(0x0014), pciephy
->membase
+ PHY_ADDR
);
80 writel(DATA_VAL(0xce10) | CAP_DATA
, pciephy
->membase
+ PHY_DATA
);
81 writel(DATA_VAL(0xce10) | WRITE_EN
, pciephy
->membase
+ PHY_DATA
);
83 writel(ADDR_VAL(0x2004), pciephy
->membase
+ PHY_ADDR
);
84 writel(DATA_VAL(0x82c7) | CAP_DATA
, pciephy
->membase
+ PHY_DATA
);
85 writel(DATA_VAL(0x82c7) | WRITE_EN
, pciephy
->membase
+ PHY_DATA
);
90 static const struct phy_ops ops
= {
91 .init
= oxnas_pcie_phy_init
,
92 .power_on
= oxnas_pcie_phy_power_on
,
96 static int oxnas_pcie_phy_probe(struct platform_device
*pdev
)
98 struct device
*dev
= &pdev
->dev
;
99 struct device_node
*np
= pdev
->dev
.of_node
;
100 struct phy
*generic_phy
;
101 struct phy_provider
*phy_provider
;
102 struct oxnas_pcie_phy
*pciephy
;
103 struct regmap
*sys_ctrl
;
104 void __iomem
*membase
;
106 membase
= of_iomap(np
, 0);
108 return PTR_ERR(membase
);
110 sys_ctrl
= syscon_regmap_lookup_by_compatible("oxsemi,ox820-sys-ctrl");
111 if (IS_ERR(sys_ctrl
)) {
112 dev_err(dev
, "Cannot find OX820 SYSCRTL\n");
113 return PTR_ERR(sys_ctrl
);
116 pciephy
= devm_kzalloc(dev
, sizeof(*pciephy
), GFP_KERNEL
);
120 pciephy
->sys_ctrl
= sys_ctrl
;
121 pciephy
->membase
= membase
;
125 generic_phy
= devm_phy_create(dev
, dev
->of_node
, pciephy
->ops
);
126 if (IS_ERR(generic_phy
)) {
127 dev_err(dev
, "failed to create PHY\n");
128 return PTR_ERR(generic_phy
);
131 phy_set_drvdata(generic_phy
, pciephy
);
132 phy_provider
= devm_of_phy_provider_register(dev
, of_phy_simple_xlate
);
134 return PTR_ERR_OR_ZERO(phy_provider
);
137 static const struct of_device_id oxnas_pcie_phy_id_table
[] = {
138 { .compatible
= "oxsemi,ox820-pcie-phy" },
142 static struct platform_driver oxnas_pcie_phy_driver
= {
143 .probe
= oxnas_pcie_phy_probe
,
145 .name
= "ox820-pcie-phy",
146 .of_match_table
= oxnas_pcie_phy_id_table
,
150 builtin_platform_driver(oxnas_pcie_phy_driver
);