blob: d292dbe0d00881559d6dbb64a8fcd2620b37ca87 [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
16static int mt798x_2p5ge_phy_config_init(struct phy_device *phydev)
17{
18 int ret;
19 int i;
20 const struct firmware *fw;
21 struct device *dev = &phydev->mdio.dev;
22 struct device_node *np;
23 void __iomem *dmb_addr;
24 void __iomem *pmb_addr;
25 void __iomem *mcucsr_base;
26 u16 reg;
27
28 np = of_find_compatible_node(NULL, NULL, "mediatek,2p5gphy-fw");
29 if (!np)
30 return -ENOENT;
31
32 dmb_addr = of_iomap(np, 0);
33 if (!dmb_addr)
34 return -ENOMEM;
35 pmb_addr = of_iomap(np, 1);
36 if (!pmb_addr)
37 return -ENOMEM;
38 mcucsr_base = of_iomap(np, 2);
39 if (!mcucsr_base)
40 return -ENOMEM;
41
42 ret = request_firmware(&fw, MEDAITEK_2P5GE_PHY_DMB_FW, dev);
43 if (ret) {
44 dev_err(dev, "failed to load firmware: %s, ret: %d\n",
45 MEDAITEK_2P5GE_PHY_DMB_FW, ret);
46 return ret;
47 }
48 for (i = 0; i < fw->size - 1; i += 4)
49 writel(*((uint32_t *)(fw->data + i)), dmb_addr + i);
50 release_firmware(fw);
51
52 ret = request_firmware(&fw, MEDIATEK_2P5GE_PHY_PMB_FW, dev);
53 if (ret) {
54 dev_err(dev, "failed to load firmware: %s, ret: %d\n",
55 MEDIATEK_2P5GE_PHY_PMB_FW, ret);
56 return ret;
57 }
58 for (i = 0; i < fw->size - 1; i += 4)
59 writel(*((uint32_t *)(fw->data + i)), pmb_addr + i);
60 release_firmware(fw);
61
62 reg = readw(mcucsr_base + MD32_EN_CFG);
63 writew(reg | MD32_EN, mcucsr_base + MD32_EN_CFG);
64 dev_info(dev, "Firmware loading/trigger ok.\n");
65
66 return 0;
67}
68
69static int mt798x_2p5ge_phy_get_features(struct phy_device *phydev)
70{
71 int ret;
72
73 ret = genphy_read_abilities(phydev);
74 if (ret)
75 return ret;
76
developerd4abc8c2022-10-28 10:45:36 +080077 /* We don't support HDX at MAC layer on mt798x.
78 * So mask phy's HDX capabilities, too.
79 */
80 linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
developer2cdaeb12022-10-04 20:25:05 +080081 phydev->supported);
82 linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
83 phydev->supported);
84 linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
85 phydev->supported);
86 linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
87 phydev->supported);
88 linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
89
90 return 0;
91}
92
93static struct phy_driver mtk_gephy_driver[] = {
94 {
95 PHY_ID_MATCH_EXACT(0x00339c11),
96 .name = "MediaTek MT798x 2.5GbE PHY",
97 .config_init = mt798x_2p5ge_phy_config_init,
98 .config_aneg = genphy_c45_config_aneg,
99 .get_features = mt798x_2p5ge_phy_get_features,
100 //.config_intr = genphy_no_config_intr,
101 //.handle_interrupt = genphy_no_ack_interrupt,
102 //.suspend = genphy_suspend,
103 //.resume = genphy_resume,
104 },
105};
106
107module_phy_driver(mtk_gephy_driver);
108
109static struct mdio_device_id __maybe_unused mtk_2p5ge_phy_tbl[] = {
110 { PHY_ID_MATCH_VENDOR(0x00339c00) },
111 { }
112};
113
114MODULE_DESCRIPTION("MediaTek 2.5Gb Ethernet PHY driver");
115MODULE_AUTHOR("SkyLake Huang <SkyLake.Huang@mediatek.com>");
116MODULE_LICENSE("GPL");
117
118MODULE_DEVICE_TABLE(mdio, mtk_2p5ge_phy_tbl);