blob: 544bb50d438ed41e7c7f91b224e76b3218b3c57e [file] [log] [blame]
developer2cdaeb12022-10-04 20:25:05 +08001// SPDX-License-Identifier: GPL-2.0+
2#include <linux/bitfield.h>
3#include <linux/firmware.h>
4#include <linux/module.h>
5#include <linux/nvmem-consumer.h>
6#include <linux/of_address.h>
7#include <linux/of_platform.h>
8#include <linux/phy.h>
9
10#define MEDAITEK_2P5GE_PHY_DMB_FW "mediatek-2p5ge-phy-dmb.bin"
11#define MEDIATEK_2P5GE_PHY_PMB_FW "mediatek-2p5ge-phy-pmb.bin"
12
13#define MD32_EN_CFG 0x18
14#define MD32_EN BIT(0)
15
developer284cd6e2022-12-15 22:19:39 +080016#define BASE100T_STATUS_EXTEND (0x10)
17#define BASE1000T_STATUS_EXTEND (0x11)
18#define EXTEND_CTRL_AND_STATUS (0x16)
19
developer2cdaeb12022-10-04 20:25:05 +080020static int mt798x_2p5ge_phy_config_init(struct phy_device *phydev)
21{
22 int ret;
23 int i;
24 const struct firmware *fw;
25 struct device *dev = &phydev->mdio.dev;
26 struct device_node *np;
27 void __iomem *dmb_addr;
28 void __iomem *pmb_addr;
29 void __iomem *mcucsr_base;
30 u16 reg;
31
32 np = of_find_compatible_node(NULL, NULL, "mediatek,2p5gphy-fw");
33 if (!np)
34 return -ENOENT;
35
36 dmb_addr = of_iomap(np, 0);
37 if (!dmb_addr)
38 return -ENOMEM;
39 pmb_addr = of_iomap(np, 1);
40 if (!pmb_addr)
41 return -ENOMEM;
42 mcucsr_base = of_iomap(np, 2);
43 if (!mcucsr_base)
44 return -ENOMEM;
45
46 ret = request_firmware(&fw, MEDAITEK_2P5GE_PHY_DMB_FW, dev);
47 if (ret) {
48 dev_err(dev, "failed to load firmware: %s, ret: %d\n",
49 MEDAITEK_2P5GE_PHY_DMB_FW, ret);
50 return ret;
51 }
52 for (i = 0; i < fw->size - 1; i += 4)
53 writel(*((uint32_t *)(fw->data + i)), dmb_addr + i);
54 release_firmware(fw);
55
56 ret = request_firmware(&fw, MEDIATEK_2P5GE_PHY_PMB_FW, dev);
57 if (ret) {
58 dev_err(dev, "failed to load firmware: %s, ret: %d\n",
59 MEDIATEK_2P5GE_PHY_PMB_FW, ret);
60 return ret;
61 }
62 for (i = 0; i < fw->size - 1; i += 4)
63 writel(*((uint32_t *)(fw->data + i)), pmb_addr + i);
64 release_firmware(fw);
65
66 reg = readw(mcucsr_base + MD32_EN_CFG);
67 writew(reg | MD32_EN, mcucsr_base + MD32_EN_CFG);
68 dev_info(dev, "Firmware loading/trigger ok.\n");
69
70 return 0;
71}
72
73static int mt798x_2p5ge_phy_get_features(struct phy_device *phydev)
74{
75 int ret;
76
77 ret = genphy_read_abilities(phydev);
78 if (ret)
79 return ret;
80
developerd4abc8c2022-10-28 10:45:36 +080081 /* We don't support HDX at MAC layer on mt798x.
82 * So mask phy's HDX capabilities, too.
83 */
84 linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
developer2cdaeb12022-10-04 20:25:05 +080085 phydev->supported);
86 linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
87 phydev->supported);
88 linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
89 phydev->supported);
90 linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
91 phydev->supported);
92 linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
93
94 return 0;
95}
96
developer284cd6e2022-12-15 22:19:39 +080097static int mt798x_2p5ge_phy_read_status(struct phy_device *phydev)
98{
99 int ret;
100 u16 reg;
101
102 ret = genphy_read_status(phydev);
103
104 reg = phy_read(phydev, BASE1000T_STATUS_EXTEND);
105 if (FIELD_GET(BIT(2), reg)) {
106 phydev->speed = SPEED_2500;
107 goto end;
108 } else if (FIELD_GET(BIT(12), reg)) {
109 phydev->speed = SPEED_1000;
110 goto end;
111 }
112
113 reg = phy_read(phydev, BASE100T_STATUS_EXTEND);
114 if (FIELD_GET(BIT(12), reg)) {
115 phydev->speed = SPEED_100;
116 goto end;
117 }
118
119 reg = phy_read(phydev, EXTEND_CTRL_AND_STATUS);
120 if (FIELD_GET(BIT(6), reg)) {
121 phydev->speed = SPEED_10;
122 goto end;
123 }
124
125end:
126 return ret;
127}
128
developer2cdaeb12022-10-04 20:25:05 +0800129static struct phy_driver mtk_gephy_driver[] = {
130 {
131 PHY_ID_MATCH_EXACT(0x00339c11),
132 .name = "MediaTek MT798x 2.5GbE PHY",
133 .config_init = mt798x_2p5ge_phy_config_init,
134 .config_aneg = genphy_c45_config_aneg,
135 .get_features = mt798x_2p5ge_phy_get_features,
developer284cd6e2022-12-15 22:19:39 +0800136 .read_status = mt798x_2p5ge_phy_read_status,
developer2cdaeb12022-10-04 20:25:05 +0800137 //.config_intr = genphy_no_config_intr,
138 //.handle_interrupt = genphy_no_ack_interrupt,
139 //.suspend = genphy_suspend,
140 //.resume = genphy_resume,
141 },
142};
143
144module_phy_driver(mtk_gephy_driver);
145
146static struct mdio_device_id __maybe_unused mtk_2p5ge_phy_tbl[] = {
147 { PHY_ID_MATCH_VENDOR(0x00339c00) },
148 { }
149};
150
151MODULE_DESCRIPTION("MediaTek 2.5Gb Ethernet PHY driver");
152MODULE_AUTHOR("SkyLake Huang <SkyLake.Huang@mediatek.com>");
153MODULE_LICENSE("GPL");
154
155MODULE_DEVICE_TABLE(mdio, mtk_2p5ge_phy_tbl);