Skip to content

Commit 41230a3

Browse files
committed
Made a start with the lan8720 ehternet phy
1 parent eaeb430 commit 41230a3

2 files changed

Lines changed: 224 additions & 0 deletions

File tree

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
#ifndef KLIB_LAN8720_HPP
2+
#define KLIB_LAN8720_HPP
3+
4+
#include <cstdint>
5+
6+
#include <klib/io/bus/ethernet.hpp>
7+
8+
namespace klib::hardware::ethernet::phy {
9+
template <typename Miim, uint8_t PhyAddress = 0x0>
10+
class lan8720a {
11+
public:
12+
// the phy address. Note the last 4 bits are the revision
13+
// number and might differ based on the hardware
14+
constexpr static uint32_t phy_id = 0x7c0f0;
15+
16+
/**
17+
* @brief Available speeds on the lan8720a when configuring
18+
*
19+
*/
20+
enum class speed {
21+
automatic,
22+
mbps_10,
23+
mbps_100,
24+
};
25+
26+
protected:
27+
/**
28+
* @brief Available registers on the lan8720a
29+
*
30+
*/
31+
enum class cmd {
32+
// basic registers
33+
basic_control = 0x00,
34+
basic_status = 0x01,
35+
36+
// extended registers
37+
phy_id_0 = 0x02,
38+
phy_id_1 = 0x03,
39+
auto_advertisement = 0x04,
40+
auto_link = 0x05,
41+
auto_expansion = 0x06,
42+
43+
// vendor specific registers
44+
mode_control_status = 0x11,
45+
special_modes = 0x12,
46+
symbol_error_counter = 0x1a,
47+
control_status_indication = 0x1b,
48+
interrupt_source = 0x1d,
49+
interrupt_mask = 0x1e,
50+
special_control_status = 0x1f
51+
};
52+
53+
/**
54+
* @brief Helper function to write to a register on the phy
55+
*
56+
* @param reg
57+
* @param value
58+
*/
59+
static void write(cmd reg, const uint16_t value) {
60+
Miim::write(PhyAddress, static_cast<uint8_t>(reg), value);
61+
}
62+
63+
/**
64+
* @brief Helper function to read from the phy
65+
*
66+
* @param reg
67+
* @return uint16_t
68+
*/
69+
static uint16_t read(cmd reg) {
70+
return Miim::read(PhyAddress, static_cast<uint8_t>(reg));
71+
}
72+
73+
public:
74+
/**
75+
* @brief Read the phy id from the Miim interface
76+
*
77+
* @return uint32_t
78+
*/
79+
static uint32_t id() {
80+
// return the combined top and bottom id register
81+
return (read(cmd::phy_id_0) << 16) | read(cmd::phy_id_1);
82+
}
83+
84+
/**
85+
* @brief Init the LAN8720A
86+
*
87+
* @tparam Speed
88+
* @tparam FullDuplex
89+
* @tparam Loopback
90+
* @tparam Isolate
91+
* @return status
92+
*/
93+
template <speed Speed = speed::automatic, bool FullDuplex = true, bool Loopback = false, bool Isolate = false>
94+
static bool init() {
95+
// do a software reset
96+
write(cmd::basic_control, (0x1 << 15));
97+
98+
// wait until the reset is done or a 250ms timeout
99+
const auto time = klib::io::systick<>::get_runtime();
100+
101+
// wait until the software reset is done or a timeout
102+
while (true) {
103+
// check if the software reset is done
104+
if (!(read(cmd::basic_control) & (0x1 << 15))) {
105+
break;
106+
}
107+
108+
// check for a timeout
109+
if ((klib::io::systick<>::get_runtime() - time) >= klib::time::ms(500)) {
110+
// lan8720 did not reset within our timeout time
111+
return false;
112+
}
113+
}
114+
115+
// make sure we have the correct phy (we ignore the last
116+
// 4 bits, the revision bits)
117+
if ((id() & (~0xf)) != phy_id) {
118+
// not a lan8720a phy
119+
return false;
120+
}
121+
122+
// write the configuration to the phy
123+
if constexpr (Speed == speed::automatic) {
124+
// in automatic mode we ignore the full duplex mode
125+
// (also overrides the speed)
126+
write(cmd::basic_control, (
127+
(0x1 << 12) | (Loopback << 14) | (Isolate << 10)
128+
));
129+
}
130+
else {
131+
write(cmd::basic_control, (
132+
((Speed == speed::mbps_100) << 13) | (Loopback << 14) |
133+
(Isolate << 10) | (FullDuplex << 8)
134+
));
135+
}
136+
137+
// return we successfully configured the lan8720a
138+
return true;
139+
}
140+
141+
/**
142+
* @brief Returns if the link is up
143+
*
144+
* @return true
145+
* @return false
146+
*/
147+
static bool has_link() {
148+
return read(cmd::basic_status) & (0x1 << 2);
149+
}
150+
151+
/**
152+
* @brief Returns the link configuration
153+
*
154+
* @note Only valid if a linked
155+
*
156+
* @return link_config
157+
*/
158+
static klib::io::ethernet::link_config get_link_config() {
159+
// read the special control status
160+
const uint16_t val = read(cmd::special_control_status);
161+
162+
// get the link speed from the
163+
const klib::io::ethernet::link_config ret = {
164+
.link_speed = (
165+
(val & (0x1 << 2)) ?
166+
klib::io::ethernet::speed::mbps_10 :
167+
klib::io::ethernet::speed::mbps_100
168+
),
169+
.full_duplex = static_cast<bool>(val & (0x1 << 4))
170+
};
171+
172+
return ret;
173+
}
174+
};
175+
}
176+
177+
#endif

klib/io/bus/ethernet.hpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#ifndef KLIB_ETHERNET_HPP
2+
#define KLIB_ETHERNET_HPP
3+
4+
#include <cstdint>
5+
#include <array>
6+
7+
namespace klib::io::ethernet {
8+
/**
9+
* @brief Media independent interfaces
10+
*
11+
*/
12+
enum class mii {
13+
mii,
14+
rmii,
15+
rgmii,
16+
};
17+
18+
/**
19+
* @brief Ethernet speeds
20+
*
21+
*/
22+
enum class speed {
23+
mbps_10,
24+
mbps_100,
25+
mbps_1000,
26+
};
27+
28+
/**
29+
* @brief Link configuration
30+
*
31+
*/
32+
struct link_config {
33+
// the link speed
34+
speed link_speed;
35+
36+
// flag if the link is full duplex
37+
bool full_duplex = true;
38+
};
39+
40+
/**
41+
* @brief Using for a mac address
42+
*
43+
*/
44+
using mac_address = std::array<uint8_t, 6>;
45+
}
46+
47+
#endif

0 commit comments

Comments
 (0)