Skip to content

Commit d20dd0e

Browse files
author
Paolo Abeni
committed
Merge branch 'microchip_t1s-update-on-microchip-10base-t1s-phy-driver'
Parthiban Veerasooran says: ==================== microchip_t1s: Update on Microchip 10BASE-T1S PHY driver This patch series contain the below updates, - Fixes on the Microchip LAN8670/1/2 10BASE-T1S PHYs support in the net/phy/microchip_t1s.c driver. - Adds support for the Microchip LAN8650/1 Rev.B0 10BASE-T1S Internal PHYs in the net/phy/microchip_t1s.c driver. ==================== Link: https://lore.kernel.org/r/20230526152348.70781-1-Parthiban.Veerasooran@microchip.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2 parents 7fa28bc + 972c6d8 commit d20dd0e

2 files changed

Lines changed: 224 additions & 55 deletions

File tree

drivers/net/phy/Kconfig

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,9 +243,10 @@ config MICREL_PHY
243243
Supports the KSZ9021, VSC8201, KS8001 PHYs.
244244

245245
config MICROCHIP_T1S_PHY
246-
tristate "Microchip 10BASE-T1S Ethernet PHY"
246+
tristate "Microchip 10BASE-T1S Ethernet PHYs"
247247
help
248-
Currently supports the LAN8670, LAN8671, LAN8672
248+
Currently supports the LAN8670/1/2 Rev.B1 and LAN8650/1 Rev.B0 Internal
249+
PHYs.
249250

250251
config MICROCHIP_PHY
251252
tristate "Microchip PHYs"

drivers/net/phy/microchip_t1s.c

Lines changed: 221 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,29 @@
11
// SPDX-License-Identifier: GPL-2.0+
22
/*
3-
* Driver for Microchip 10BASE-T1S LAN867X PHY
3+
* Driver for Microchip 10BASE-T1S PHYs
44
*
55
* Support: Microchip Phys:
6-
* lan8670, lan8671, lan8672
6+
* lan8670/1/2 Rev.B1
7+
* lan8650/1 Rev.B0 Internal PHYs
78
*/
89

910
#include <linux/kernel.h>
1011
#include <linux/module.h>
1112
#include <linux/phy.h>
1213

13-
#define PHY_ID_LAN867X 0x0007C160
14+
#define PHY_ID_LAN867X_REVB1 0x0007C162
15+
#define PHY_ID_LAN865X_REVB0 0x0007C1B3
1416

15-
#define LAN867X_REG_IRQ_1_CTL 0x001C
16-
#define LAN867X_REG_IRQ_2_CTL 0x001D
17+
#define LAN867X_REG_STS2 0x0019
18+
19+
#define LAN867x_RESET_COMPLETE_STS BIT(11)
20+
21+
#define LAN865X_REG_CFGPARAM_ADDR 0x00D8
22+
#define LAN865X_REG_CFGPARAM_DATA 0x00D9
23+
#define LAN865X_REG_CFGPARAM_CTRL 0x00DA
24+
#define LAN865X_REG_STS2 0x0019
25+
26+
#define LAN865X_CFGPARAM_READ_ENABLE BIT(1)
1727

1828
/* The arrays below are pulled from the following table from AN1699
1929
* Access MMD Address Value Mask
@@ -31,72 +41,219 @@
3141
* W 0x1F 0x0099 0x7F80 ------
3242
*/
3343

34-
static const int lan867x_fixup_registers[12] = {
44+
static const u32 lan867x_revb1_fixup_registers[12] = {
3545
0x00D0, 0x00D1, 0x0084, 0x0085,
3646
0x008A, 0x0087, 0x0088, 0x008B,
3747
0x0080, 0x00F1, 0x0096, 0x0099,
3848
};
3949

40-
static const int lan867x_fixup_values[12] = {
50+
static const u16 lan867x_revb1_fixup_values[12] = {
4151
0x0002, 0x0000, 0x3380, 0x0006,
4252
0xC000, 0x801C, 0x033F, 0x0404,
4353
0x0600, 0x2400, 0x2000, 0x7F80,
4454
};
4555

46-
static const int lan867x_fixup_masks[12] = {
56+
static const u16 lan867x_revb1_fixup_masks[12] = {
4757
0x0E03, 0x0300, 0xFFC0, 0x000F,
4858
0xF800, 0x801C, 0x1FFF, 0xFFFF,
4959
0x0600, 0x7F00, 0x2000, 0xFFFF,
5060
};
5161

52-
static int lan867x_config_init(struct phy_device *phydev)
62+
/* LAN865x Rev.B0 configuration parameters from AN1760 */
63+
static const u32 lan865x_revb0_fixup_registers[28] = {
64+
0x0091, 0x0081, 0x0043, 0x0044,
65+
0x0045, 0x0053, 0x0054, 0x0055,
66+
0x0040, 0x0050, 0x00D0, 0x00E9,
67+
0x00F5, 0x00F4, 0x00F8, 0x00F9,
68+
0x00B0, 0x00B1, 0x00B2, 0x00B3,
69+
0x00B4, 0x00B5, 0x00B6, 0x00B7,
70+
0x00B8, 0x00B9, 0x00BA, 0x00BB,
71+
};
72+
73+
static const u16 lan865x_revb0_fixup_values[28] = {
74+
0x9660, 0x00C0, 0x00FF, 0xFFFF,
75+
0x0000, 0x00FF, 0xFFFF, 0x0000,
76+
0x0002, 0x0002, 0x5F21, 0x9E50,
77+
0x1CF8, 0xC020, 0x9B00, 0x4E53,
78+
0x0103, 0x0910, 0x1D26, 0x002A,
79+
0x0103, 0x070D, 0x1720, 0x0027,
80+
0x0509, 0x0E13, 0x1C25, 0x002B,
81+
};
82+
83+
static const u16 lan865x_revb0_fixup_cfg_regs[5] = {
84+
0x0084, 0x008A, 0x00AD, 0x00AE, 0x00AF
85+
};
86+
87+
/* Pulled from AN1760 describing 'indirect read'
88+
*
89+
* write_register(0x4, 0x00D8, addr)
90+
* write_register(0x4, 0x00DA, 0x2)
91+
* return (int8)(read_register(0x4, 0x00D9))
92+
*
93+
* 0x4 refers to memory map selector 4, which maps to MDIO_MMD_VEND2
94+
*/
95+
static int lan865x_revb0_indirect_read(struct phy_device *phydev, u16 addr)
96+
{
97+
int ret;
98+
99+
ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, LAN865X_REG_CFGPARAM_ADDR,
100+
addr);
101+
if (ret)
102+
return ret;
103+
104+
ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, LAN865X_REG_CFGPARAM_CTRL,
105+
LAN865X_CFGPARAM_READ_ENABLE);
106+
if (ret)
107+
return ret;
108+
109+
return phy_read_mmd(phydev, MDIO_MMD_VEND2, LAN865X_REG_CFGPARAM_DATA);
110+
}
111+
112+
/* This is pulled straight from AN1760 from 'calculation of offset 1' &
113+
* 'calculation of offset 2'
114+
*/
115+
static int lan865x_generate_cfg_offsets(struct phy_device *phydev, s8 offsets[2])
116+
{
117+
const u16 fixup_regs[2] = {0x0004, 0x0008};
118+
int ret;
119+
120+
for (int i = 0; i < ARRAY_SIZE(fixup_regs); i++) {
121+
ret = lan865x_revb0_indirect_read(phydev, fixup_regs[i]);
122+
if (ret < 0)
123+
return ret;
124+
if (ret & BIT(4))
125+
offsets[i] = ret | 0xE0;
126+
else
127+
offsets[i] = ret;
128+
}
129+
130+
return 0;
131+
}
132+
133+
static int lan865x_read_cfg_params(struct phy_device *phydev, u16 cfg_params[])
134+
{
135+
int ret;
136+
137+
for (int i = 0; i < ARRAY_SIZE(lan865x_revb0_fixup_cfg_regs); i++) {
138+
ret = phy_read_mmd(phydev, MDIO_MMD_VEND2,
139+
lan865x_revb0_fixup_cfg_regs[i]);
140+
if (ret < 0)
141+
return ret;
142+
cfg_params[i] = (u16)ret;
143+
}
144+
145+
return 0;
146+
}
147+
148+
static int lan865x_write_cfg_params(struct phy_device *phydev, u16 cfg_params[])
53149
{
54-
/* HW quirk: Microchip states in the application note (AN1699) for the phy
55-
* that a set of read-modify-write (rmw) operations has to be performed
56-
* on a set of seemingly magic registers.
57-
* The result of these operations is just described as 'optimal performance'
58-
* Microchip gives no explanation as to what these mmd regs do,
59-
* in fact they are marked as reserved in the datasheet.
60-
* It is unclear if phy_modify_mmd would be safe to use or if a write
61-
* really has to happen to each register.
62-
* In order to exactly conform to what is stated in the AN phy_write_mmd is
63-
* used, which might then write the same value back as read + modified.
150+
int ret;
151+
152+
for (int i = 0; i < ARRAY_SIZE(lan865x_revb0_fixup_cfg_regs); i++) {
153+
ret = phy_write_mmd(phydev, MDIO_MMD_VEND2,
154+
lan865x_revb0_fixup_cfg_regs[i],
155+
cfg_params[i]);
156+
if (ret)
157+
return ret;
158+
}
159+
160+
return 0;
161+
}
162+
163+
static int lan865x_setup_cfgparam(struct phy_device *phydev)
164+
{
165+
u16 cfg_params[ARRAY_SIZE(lan865x_revb0_fixup_cfg_regs)];
166+
u16 cfg_results[5];
167+
s8 offsets[2];
168+
int ret;
169+
170+
ret = lan865x_generate_cfg_offsets(phydev, offsets);
171+
if (ret)
172+
return ret;
173+
174+
ret = lan865x_read_cfg_params(phydev, cfg_params);
175+
if (ret)
176+
return ret;
177+
178+
cfg_results[0] = (cfg_params[0] & 0x000F) |
179+
FIELD_PREP(GENMASK(15, 10), 9 + offsets[0]) |
180+
FIELD_PREP(GENMASK(15, 4), 14 + offsets[0]);
181+
cfg_results[1] = (cfg_params[1] & 0x03FF) |
182+
FIELD_PREP(GENMASK(15, 10), 40 + offsets[1]);
183+
cfg_results[2] = (cfg_params[2] & 0xC0C0) |
184+
FIELD_PREP(GENMASK(15, 8), 5 + offsets[0]) |
185+
(9 + offsets[0]);
186+
cfg_results[3] = (cfg_params[3] & 0xC0C0) |
187+
FIELD_PREP(GENMASK(15, 8), 9 + offsets[0]) |
188+
(14 + offsets[0]);
189+
cfg_results[4] = (cfg_params[4] & 0xC0C0) |
190+
FIELD_PREP(GENMASK(15, 8), 17 + offsets[0]) |
191+
(22 + offsets[0]);
192+
193+
return lan865x_write_cfg_params(phydev, cfg_results);
194+
}
195+
196+
static int lan865x_revb0_config_init(struct phy_device *phydev)
197+
{
198+
int ret;
199+
200+
/* Reference to AN1760
201+
* https://ww1.microchip.com/downloads/aemDocuments/documents/AIS/ProductDocuments/SupportingCollateral/AN-LAN8650-1-Configuration-60001760.pdf
202+
*/
203+
for (int i = 0; i < ARRAY_SIZE(lan865x_revb0_fixup_registers); i++) {
204+
ret = phy_write_mmd(phydev, MDIO_MMD_VEND2,
205+
lan865x_revb0_fixup_registers[i],
206+
lan865x_revb0_fixup_values[i]);
207+
if (ret)
208+
return ret;
209+
}
210+
/* Function to calculate and write the configuration parameters in the
211+
* 0x0084, 0x008A, 0x00AD, 0x00AE and 0x00AF registers (from AN1760)
64212
*/
213+
return lan865x_setup_cfgparam(phydev);
214+
}
65215

66-
int reg_value;
216+
static int lan867x_revb1_config_init(struct phy_device *phydev)
217+
{
67218
int err;
68-
int reg;
69219

70-
/* Read-Modified Write Pseudocode (from AN1699)
71-
* current_val = read_register(mmd, addr) // Read current register value
72-
* new_val = current_val AND (NOT mask) // Clear bit fields to be written
73-
* new_val = new_val OR value // Set bits
74-
* write_register(mmd, addr, new_val) // Write back updated register value
220+
/* The chip completes a reset in 3us, we might get here earlier than
221+
* that, as an added margin we'll conditionally sleep 5us.
75222
*/
76-
for (int i = 0; i < ARRAY_SIZE(lan867x_fixup_registers); i++) {
77-
reg = lan867x_fixup_registers[i];
78-
reg_value = phy_read_mmd(phydev, MDIO_MMD_VEND2, reg);
79-
reg_value &= ~lan867x_fixup_masks[i];
80-
reg_value |= lan867x_fixup_values[i];
81-
err = phy_write_mmd(phydev, MDIO_MMD_VEND2, reg, reg_value);
82-
if (err != 0)
223+
err = phy_read_mmd(phydev, MDIO_MMD_VEND2, LAN867X_REG_STS2);
224+
if (err < 0)
225+
return err;
226+
227+
if (!(err & LAN867x_RESET_COMPLETE_STS)) {
228+
udelay(5);
229+
err = phy_read_mmd(phydev, MDIO_MMD_VEND2, LAN867X_REG_STS2);
230+
if (err < 0)
83231
return err;
232+
if (!(err & LAN867x_RESET_COMPLETE_STS)) {
233+
phydev_err(phydev, "PHY reset failed\n");
234+
return -ENODEV;
235+
}
84236
}
85237

86-
/* None of the interrupts in the lan867x phy seem relevant.
87-
* Other phys inspect the link status and call phy_trigger_machine
88-
* in the interrupt handler.
89-
* This phy does not support link status, and thus has no interrupt
90-
* for it either.
91-
* So we'll just disable all interrupts on the chip.
238+
/* Reference to AN1699
239+
* https://ww1.microchip.com/downloads/aemDocuments/documents/AIS/ProductDocuments/SupportingCollateral/AN-LAN8670-1-2-config-60001699.pdf
240+
* AN1699 says Read, Modify, Write, but the Write is not required if the
241+
* register already has the required value. So it is safe to use
242+
* phy_modify_mmd here.
92243
*/
93-
err = phy_write_mmd(phydev, MDIO_MMD_VEND2, LAN867X_REG_IRQ_1_CTL, 0xFFFF);
94-
if (err != 0)
95-
return err;
96-
return phy_write_mmd(phydev, MDIO_MMD_VEND2, LAN867X_REG_IRQ_2_CTL, 0xFFFF);
244+
for (int i = 0; i < ARRAY_SIZE(lan867x_revb1_fixup_registers); i++) {
245+
err = phy_modify_mmd(phydev, MDIO_MMD_VEND2,
246+
lan867x_revb1_fixup_registers[i],
247+
lan867x_revb1_fixup_masks[i],
248+
lan867x_revb1_fixup_values[i]);
249+
if (err)
250+
return err;
251+
}
252+
253+
return 0;
97254
}
98255

99-
static int lan867x_read_status(struct phy_device *phydev)
256+
static int lan86xx_read_status(struct phy_device *phydev)
100257
{
101258
/* The phy has some limitations, namely:
102259
* - always reports link up
@@ -111,28 +268,39 @@ static int lan867x_read_status(struct phy_device *phydev)
111268
return 0;
112269
}
113270

114-
static struct phy_driver lan867x_driver[] = {
271+
static struct phy_driver microchip_t1s_driver[] = {
115272
{
116-
PHY_ID_MATCH_MODEL(PHY_ID_LAN867X),
117-
.name = "LAN867X",
273+
PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVB1),
274+
.name = "LAN867X Rev.B1",
118275
.features = PHY_BASIC_T1S_P2MP_FEATURES,
119-
.config_init = lan867x_config_init,
120-
.read_status = lan867x_read_status,
276+
.config_init = lan867x_revb1_config_init,
277+
.read_status = lan86xx_read_status,
121278
.get_plca_cfg = genphy_c45_plca_get_cfg,
122279
.set_plca_cfg = genphy_c45_plca_set_cfg,
123280
.get_plca_status = genphy_c45_plca_get_status,
124-
}
281+
},
282+
{
283+
PHY_ID_MATCH_EXACT(PHY_ID_LAN865X_REVB0),
284+
.name = "LAN865X Rev.B0 Internal Phy",
285+
.features = PHY_BASIC_T1S_P2MP_FEATURES,
286+
.config_init = lan865x_revb0_config_init,
287+
.read_status = lan86xx_read_status,
288+
.get_plca_cfg = genphy_c45_plca_get_cfg,
289+
.set_plca_cfg = genphy_c45_plca_set_cfg,
290+
.get_plca_status = genphy_c45_plca_get_status,
291+
},
125292
};
126293

127-
module_phy_driver(lan867x_driver);
294+
module_phy_driver(microchip_t1s_driver);
128295

129296
static struct mdio_device_id __maybe_unused tbl[] = {
130-
{ PHY_ID_MATCH_MODEL(PHY_ID_LAN867X) },
297+
{ PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVB1) },
298+
{ PHY_ID_MATCH_EXACT(PHY_ID_LAN865X_REVB0) },
131299
{ }
132300
};
133301

134302
MODULE_DEVICE_TABLE(mdio, tbl);
135303

136-
MODULE_DESCRIPTION("Microchip 10BASE-T1S lan867x Phy driver");
304+
MODULE_DESCRIPTION("Microchip 10BASE-T1S PHYs driver");
137305
MODULE_AUTHOR("Ramón Nordin Rodriguez");
138306
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)