Skip to content

Commit b977f87

Browse files
maass-hamburgrobhancocksed
authored andcommitted
drivers: ethernet: phy: microchip_vsc8541: improve driver
- implement configure link - support half duplex - use defines from mii.h - fix check ret vals Signed-off-by: Fin Maaß <f.maass@vogl-electronic.com> Signed-off-by: Fin Maaß <f.maass@vogl-electronic.com>
1 parent 6d9feca commit b977f87

File tree

1 file changed

+70
-117
lines changed

1 file changed

+70
-117
lines changed

drivers/ethernet/phy/phy_microchip_vsc8541.c

Lines changed: 70 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ LOG_MODULE_REGISTER(microchip_vsc8541, CONFIG_PHY_LOG_LEVEL);
1616
#include <zephyr/sys/util_macro.h>
1717
#include <zephyr/drivers/gpio.h>
1818

19+
#include "phy_mii.h"
20+
1921
/* phy page selectors */
2022
#define PHY_PAGE_0 0x00 /* main registers space active */
2123
#define PHY_PAGE_1 0x01 /* reg 16 - 30 will be redirected to ext. register space 1 */
@@ -26,25 +28,14 @@ LOG_MODULE_REGISTER(microchip_vsc8541, CONFIG_PHY_LOG_LEVEL);
2628
#define PHY_REG(page, reg) ((page << 8) | (reg << 0))
2729

2830
/* Generic Register */
29-
#define PHY_REG_PAGE0_BMCR PHY_REG(PHY_PAGE_0, 0x00)
30-
#define PHY_REG_PAGE0_BMSR PHY_REG(PHY_PAGE_0, 0x01)
31-
#define PHY_REG_PAGE0_ID1 PHY_REG(PHY_PAGE_0, 0x02)
32-
#define PHY_REG_PAGE0_ID2 PHY_REG(PHY_PAGE_0, 0x03)
33-
#define PHY_REG_PAGE0_ADV PHY_REG(PHY_PAGE_0, 0x04)
34-
#define PHY_REG_LPA 0x05
35-
#define PHY_REG_EXP 0x06
36-
#define PHY_REG_PAGE0_CTRL1000 PHY_REG(PHY_PAGE_0, 0x09)
37-
#define PHY_REG_PAGE0_STAT1000 PHY_REG(0, 0x0A)
38-
#define PHY_REG_MMD_CTRL 0x0D
39-
#define PHY_REG_MMD_DATA 0x0E
40-
#define PHY_REG_STAT1000_EXT1 0x0F
4131
#define PHY_REG_PAGE0_STAT100 PHY_REG(PHY_PAGE_0, 0x10)
4232
#define PHY_REG_PAGE0_STAT1000_EXT2 PHY_REG(PHY_PAGE_0, 0x11)
4333
#define PHY_REG_AUX_CTRL 0x12
4434
#define PHY_REG_PAGE0_ERROR_COUNTER_1 PHY_REG(0, 0x13)
4535
#define PHY_REG_PAGE0_ERROR_COUNTER_2 PHY_REG(0, 0x14)
4636
#define PHY_REG_PAGE0_EXT_CTRL_STAT PHY_REG(PHY_PAGE_0, 0x16)
4737
#define PHY_REG_PAGE0_EXT_CONTROL_1 PHY_REG(PHY_PAGE_0, 0x17)
38+
#define PHY_REG_PAGE0_EXT_DEV_AUX PHY_REG(PHY_PAGE_0, 0x1C)
4839
#define PHY_REG_LED_MODE 0x1d
4940

5041
#define PHY_REG_PAGE_SELECTOR 0x1F
@@ -54,19 +45,7 @@ LOG_MODULE_REGISTER(microchip_vsc8541, CONFIG_PHY_LOG_LEVEL);
5445
#define PHY_REG_PAGE2_RGMII_CONTROL PHY_REG(PHY_PAGE_2, 0x14)
5546
#define PHY_REG_PAGE2_MAC_IF_CONTROL PHY_REG(PHY_PAGE_2, 0x1b)
5647

57-
/* selected bits in registers */
58-
#define BMCR_RESET (1 << 15)
59-
#define BMCR_LOOPBACK (1 << 14)
60-
#define BMCR_ANENABLE (1 << 12)
61-
#define BMCR_ANRESTART (1 << 9)
62-
#define BMCR_FULLDPLX (1 << 8)
63-
#define BMCR_SPEED10 ((0 << 13) | (0 << 6))
64-
#define BMCR_SPEED100 ((1 << 13) | (0 << 6))
65-
#define BMCR_SPEED1000 ((0 << 13) | (1 << 6))
66-
67-
#define BMCR_SPEEDMASK ((1 << 13) | (1 << 6))
68-
69-
#define BMSR_LSTATUS (1 << 2)
48+
#define PHY_REG_PAGE0_EXT_DEV_AUX_DUPLEX BIT(5)
7049

7150
enum vsc8541_interface {
7251
VSC8541_MII,
@@ -123,11 +102,11 @@ static int phy_mc_vsc8541_verify_phy_id(const struct device *dev)
123102
uint16_t phy_id_1;
124103
uint16_t phy_id_2;
125104

126-
if (0 != phy_mc_vsc8541_read(dev, PHY_REG_PAGE0_ID1, (uint32_t *)&phy_id_1)) {
105+
if (phy_mc_vsc8541_read(dev, MII_PHYID1R, (uint32_t *)&phy_id_1) < 0) {
127106
return -EINVAL;
128107
}
129108

130-
if (0 != phy_mc_vsc8541_read(dev, PHY_REG_PAGE0_ID2, (uint32_t *)&phy_id_2)) {
109+
if (phy_mc_vsc8541_read(dev, MII_PHYID2R, (uint32_t *)&phy_id_2) < 0) {
131110
return -EINVAL;
132111
}
133112

@@ -153,6 +132,8 @@ static int phy_mc_vsc8541_verify_phy_id(const struct device *dev)
153132
static int phy_mc_vsc8541_reset(const struct device *dev)
154133
{
155134
const struct mc_vsc8541_config *cfg = dev->config;
135+
int ret;
136+
uint32_t reg = 0U;
156137

157138
#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(reset_gpios)
158139

@@ -162,16 +143,15 @@ static int phy_mc_vsc8541_reset(const struct device *dev)
162143
}
163144

164145
/* configure the reset pin */
165-
int ret = gpio_pin_configure_dt(&cfg->reset_gpio, GPIO_OUTPUT_ACTIVE);
166-
167-
if (ret) {
146+
ret = gpio_pin_configure_dt(&cfg->reset_gpio, GPIO_OUTPUT_ACTIVE);
147+
if (ret < 0) {
168148
return ret;
169149
}
170150

171151
for (uint32_t i = 0; i < 2; i++) {
172152
/* Start reset */
173153
ret = gpio_pin_set_dt(&cfg->reset_gpio, 0);
174-
if (ret) {
154+
if (ret < 0) {
175155
LOG_WRN("failed to set reset gpio");
176156
return -EINVAL;
177157
}
@@ -194,7 +174,7 @@ static int phy_mc_vsc8541_reset(const struct device *dev)
194174

195175
#if CONFIG_PHY_VERIFY_DEVICE_IDENTIFICATION
196176
/* confirm phy organizationally unique identifier, if enabled */
197-
if (0 != phy_mc_vsc8541_verify_phy_id(dev)) {
177+
if (phy_mc_vsc8541_verify_phy_id(dev) < 0) {
198178
LOG_ERR("failed to verify phy id");
199179
return -EINVAL;
200180
}
@@ -204,62 +184,30 @@ static int phy_mc_vsc8541_reset(const struct device *dev)
204184
if (cfg->microchip_interface_type == VSC8541_RGMII) {
205185
ret = phy_mc_vsc8541_write(dev, PHY_REG_PAGE0_EXT_CONTROL_1,
206186
(0x0 << 13) | (0x2 << 11));
207-
if (ret) {
187+
if (ret < 0) {
208188
return ret;
209189
}
210190
}
211191

212192
/* software reset */
213-
ret = phy_mc_vsc8541_write(dev, PHY_REG_PAGE0_BMCR, MII_BMCR_RESET);
214-
if (ret) {
193+
ret = phy_mc_vsc8541_write(dev, MII_BMCR, MII_BMCR_RESET);
194+
if (ret < 0) {
215195
return ret;
216196
}
217197

218198
/* wait for phy finished software reset */
219-
uint32_t reg = 0;
220-
221199
do {
222-
phy_mc_vsc8541_read(dev, PHY_REG_PAGE0_BMCR, &reg);
223-
} while (reg & BMCR_RESET);
224-
225-
/* forced MDI-X */
226-
ret = phy_mc_vsc8541_write(dev, PHY_REG_PAGE1_EXT_MODE_CTRL, (3 << 2));
227-
if (ret) {
228-
return ret;
229-
}
200+
phy_mc_vsc8541_read(dev, MII_BMCR, &reg);
201+
} while (reg & MII_BMCR_RESET);
230202

231203
/* configure the RGMII clk delay */
232204
reg = 0x0;
233205
/* RX_CLK delay */
234206
reg |= (cfg->rgmii_rx_clk_delay << 4);
235207
/* TX_CLK delay */
236208
reg |= (cfg->rgmii_tx_clk_delay << 0);
237-
ret = phy_mc_vsc8541_write(dev, PHY_REG_PAGE2_RGMII_CONTROL, reg);
238-
if (ret) {
239-
return ret;
240-
}
241-
242-
/* we use limited advertising, to force gigabit speed */
243-
/* initial version of this driver supports only 1GB/s */
244-
245-
/* 1000MBit/s + AUTO */
246-
ret = phy_mc_vsc8541_write(dev, PHY_REG_PAGE0_ADV, (1 << 8) | (1 << 6) | 0x01);
247-
if (ret) {
248-
return ret;
249-
}
250-
251-
ret = phy_mc_vsc8541_write(dev, PHY_REG_PAGE0_CTRL1000, (1 << 12) | (1 << 11) | (1 << 9));
252-
if (ret) {
253-
return ret;
254-
}
255-
256-
/* start auto negotiation */
257-
ret = phy_mc_vsc8541_write(dev, PHY_REG_PAGE0_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
258-
if (ret) {
259-
return ret;
260-
}
261209

262-
return ret;
210+
return phy_mc_vsc8541_write(dev, PHY_REG_PAGE2_RGMII_CONTROL, reg);
263211
}
264212

265213
/**
@@ -271,72 +219,79 @@ static int phy_mc_vsc8541_reset(const struct device *dev)
271219
static int phy_mc_vsc8541_get_speed(const struct device *dev, struct phy_link_state *state)
272220
{
273221
int ret;
274-
uint32_t status;
222+
uint32_t aux_status;
275223
uint32_t link10_status;
276224
uint32_t link100_status;
277225
uint32_t link1000_status;
226+
bool is_duplex;
278227

279-
ret = phy_mc_vsc8541_read(dev, PHY_REG_PAGE0_BMSR, &status);
280-
if (ret) {
228+
ret = phy_mc_vsc8541_read(dev, PHY_REG_PAGE0_EXT_DEV_AUX, &aux_status);
229+
if (ret < 0) {
281230
return ret;
282231
}
283232

284-
ret = phy_mc_vsc8541_read(dev, PHY_REG_PAGE0_EXT_CTRL_STAT, &link10_status);
285-
if (ret) {
233+
is_duplex = (aux_status & PHY_REG_PAGE0_EXT_DEV_AUX_DUPLEX) != 0;
234+
235+
ret = phy_mc_vsc8541_read(dev, PHY_REG_PAGE0_STAT1000_EXT2, &link1000_status);
236+
if (ret < 0) {
286237
return ret;
287238
}
288239

289-
ret = phy_mc_vsc8541_read(dev, PHY_REG_PAGE0_STAT100, &link100_status);
290-
if (ret) {
291-
return ret;
240+
if ((link1000_status & BIT(12))) {
241+
state->speed = is_duplex ? LINK_FULL_1000BASE : LINK_HALF_1000BASE;
242+
return 0; /* no need to check lower speeds */
292243
}
293244

294-
ret = phy_mc_vsc8541_read(dev, PHY_REG_PAGE0_STAT1000_EXT2, &link1000_status);
295-
if (ret) {
245+
ret = phy_mc_vsc8541_read(dev, PHY_REG_PAGE0_STAT100, &link100_status);
246+
if (ret < 0) {
296247
return ret;
297248
}
298249

299-
if ((status & (1 << 2)) == 0) {
300-
/* no link */
301-
state->speed = LINK_HALF_10BASE;
250+
if (link100_status & BIT(12)) {
251+
state->speed = is_duplex ? LINK_FULL_100BASE : LINK_HALF_100BASE;
252+
return 0; /* no need to check lower speeds */
302253
}
303254

304-
if ((status & (1 << 5)) == 0) {
305-
/* auto negotiation not yet complete */
306-
state->speed = LINK_HALF_10BASE;
255+
ret = phy_mc_vsc8541_read(dev, PHY_REG_PAGE0_EXT_CTRL_STAT, &link10_status);
256+
if (ret < 0) {
257+
return ret;
307258
}
308259

309-
if ((link1000_status & (1 << 12))) {
310-
state->speed = LINK_FULL_1000BASE;
311-
}
312-
if (link100_status & (1 << 12)) {
313-
state->speed = LINK_FULL_100BASE;
314-
}
315-
if (link10_status & (1 << 6)) {
316-
state->speed = LINK_FULL_10BASE;
260+
if (link10_status & BIT(6)) {
261+
state->speed = is_duplex ? LINK_FULL_10BASE : LINK_HALF_10BASE;
262+
} else {
263+
state->speed = 0; /* no link */
317264
}
318265

319266
return 0;
320267
}
321268

269+
static int phy_mc_vsc8541_cfg_link(const struct device *dev, enum phy_link_speed adv_speeds,
270+
enum phy_cfg_link_flag flags)
271+
{
272+
if (flags & PHY_FLAG_AUTO_NEGOTIATION_DISABLED) {
273+
LOG_ERR("Disabling auto-negotiation is not supported by this driver");
274+
return -ENOTSUP;
275+
}
276+
277+
return phy_mii_cfg_link_autoneg(dev, adv_speeds, true);
278+
}
279+
322280
/**
323281
* @brief Initializes the phy and starts the link monitor
324282
*
325283
*/
326284
static int phy_mc_vsc8541_init(const struct device *dev)
327285
{
328286
struct mc_vsc8541_data *data = dev->data;
287+
struct mc_vsc8541_config *cfg = dev->config;
288+
int ret;
329289

330-
data->cb = NULL;
331-
data->cb_data = NULL;
332-
data->state.is_up = false;
333-
data->state.speed = LINK_HALF_10BASE;
334290
data->active_page = -1;
335291

336292
/* Reset PHY */
337-
int ret = phy_mc_vsc8541_reset(dev);
338-
339-
if (ret) {
293+
ret = phy_mc_vsc8541_reset(dev);
294+
if (ret < 0) {
340295
LOG_ERR("initialize failed");
341296
return ret;
342297
}
@@ -363,37 +318,35 @@ static int phy_mc_vsc8541_get_link(const struct device *dev, struct phy_link_sta
363318
int ret;
364319
uint32_t reg_sr;
365320
uint32_t reg_cr;
321+
bool hasLink;
322+
bool auto_negotiation_finished = true;
366323

367-
ret = phy_mc_vsc8541_read(dev, PHY_REG_PAGE0_BMSR, &reg_sr);
368-
if (ret) {
324+
ret = phy_mc_vsc8541_read(dev, MII_BMSR, &reg_sr);
325+
if (ret < 0) {
369326
return ret;
370327
}
371328

372-
ret = phy_mc_vsc8541_read(dev, PHY_REG_PAGE0_BMCR, &reg_cr);
373-
if (ret) {
329+
ret = phy_mc_vsc8541_read(dev, MII_BMCR, &reg_cr);
330+
if (ret < 0) {
374331
return ret;
375332
}
376333

377-
uint32_t hasLink = reg_sr & (1 << 2) ? 1 : 0;
334+
hasLink = (reg_sr & MII_BMSR_LINK_STATUS) != 0;
378335

379-
uint32_t auto_negotiation_finished;
380-
381-
if (reg_cr & (BMCR_ANENABLE)) {
336+
if (reg_cr & MII_BMCR_AUTONEG_ENABLE) {
382337
/* auto negotiation active; update status */
383-
auto_negotiation_finished = reg_sr & (1 << 5) ? 1 : 0;
384-
} else {
385-
auto_negotiation_finished = 1;
338+
auto_negotiation_finished = (reg_sr & MII_BMSR_AUTONEG_COMPLETE) != 0;
386339
}
387340

388-
if (hasLink & auto_negotiation_finished) {
389-
state->is_up = 1;
341+
if (hasLink && auto_negotiation_finished) {
342+
state->is_up = true;
390343
ret = phy_mc_vsc8541_get_speed(dev, state);
391-
if (ret) {
344+
if (ret < 0) {
392345
return ret;
393346
}
394347
} else {
395-
state->is_up = 0;
396-
state->speed = LINK_HALF_10BASE;
348+
state->is_up = false;
349+
state->speed = 0;
397350
}
398351

399352
return 0;

0 commit comments

Comments
 (0)