My mdio acces script attached.
Regards,
Pavel
On 1/19/21 2:08 AM, Pavel Šimerda wrote:
Hi Tobias,
given the reasons stated in the mailing list, I'd like to discuss the situation
off-list. I would be more than happy to join your effort and provide an OpenWRT
package. I understand the motivation to reject that, and I do use it partially
also for the “bad purpose” and therefore I'd like to solve it as consistently
as possible.
I'm working with mv88e6xxx where c45 can be coded in c22 anyway, so I didn't
care to implement it in the MDIO driver. I'd like to share with you the user
space script I'm using to access both mv88e6xxx and direct PHY registers.
I see you're working with mv88e6xxx as well. Can you access all of the inderect
registers up to multichip+indirect+paged/c45 registers even without the
mv88e6xxx driver loaded, or not? I'm using this feature to bootstrap the switch
and get it onto the network when the driver doesn't work yet.
I've seen a few new patches submitted to next-next regarding mv88e6393 and the
lag support. I'm also going to explore MSTP and more. I published some of my
changes that might not be accepted upstream any soon, or like this one, at all:
https://github.com/switchwrt
Regards,
Pavel
#!/bin/sh
IFS=,
if [ -z "$MDIO_CONTROL" ]; then
MDIO_CONTROL=/sys/kernel/debug/mdio/f0028000.ethernet/control
fi
verbose=
phy_chipaddr=
phy_page=
phy_address=
phy_device=
phy_offset=
phy_bits=
phy_value=
while [ $# != 0 ]; do
case $1 in
-v|--verbose)
verbose=1
;;
-n|--no-write)
no_write=1
;;
-L|--link)
MDIO_CONTROL=/sys/kernel/debug/mdio/f802c000.ethernet/control
;;
-S|--switch)
MDIO_CONTROL=/sys/kernel/debug/mdio/f0028000.ethernet/control
;;
-P|--phy)
MDIO_CONTROL=$(echo
/sys/kernel/debug/mdio/!ahb!apb!ethernet@f0028000!switch0@*!mdio/control)
;;
-m|--multichip)
shift
phy_chipaddr=$1
;;
-p|--page)
shift
phy_page=$1
;;
-a|--address)
shift
phy_addresses=$1
;;
-d|--device)
shift
phy_device=$1
;;
-o|--offset)
shift
phy_offset=$1
;;
-b|--bits)
shift
phy_bits=$1
;;
-w|--write)
shift
phy_value=$1
;;
esac
shift
done
parse_bits() {
bit_stop=${1%:*}
bit_start=${1#*:}
bit_stop=$((bit_stop + 1))
}
_get_bits() {
local bit_start bit_stop
parse_bits "$1"
value="$2"
printf "0x%.04x\n" "$(( (value & ((1<<bit_stop) - 1)) >> bit_start ))"
}
_set_bits() {
local original="$1"
local bit_start bit_stop
parse_bits "$2"
local value="$3"
local mask="$(( (1<<bit_stop) - (1<<bit_start) ))"
printf "0x%.04x\n" "$(( (original & ~mask) | ((value << bit_start) &
mask) ))"
}
direct_cmd() {
echo -n "$1" >&3
}
direct_read() {
direct_cmd $(printf "%.2x:%.2x\n" "$1" "$2")
echo "0x$(head -n 1 <&3)"
}
direct_write() {
direct_cmd $(printf "%.2x:%.2x:%.4x\n" "$1" "$2" "$3")
}
indirect_wait() {
ret=$(direct_read "$phy_chipaddr" 0x00)
while [ $(( ret & 0x8000 )) != 0 ]; do
sleep 1
ret=$(direct_read "$phy_chipaddr" 0x00)
done
}
indirect_read() {
address="$1"
offset="$2"
cmd=$(printf "0x%.4x" "$(( 0x9800 | ((address & 0x1f) << 5) | (offset &
0x1f) ))")
indirect_wait
direct_write "$phy_chipaddr" 0x00 "$cmd"
indirect_wait
direct_read "$phy_chipaddr" 0x01
}
indirect_write() {
address="$1"
offset="$2"
data="$3"
cmd=$(printf "0x%.4x" "$(( 0x9400 | ((address & 0x1f) << 5) | (offset &
0x1f) ))")
indirect_wait
direct_write "$phy_chipaddr" 0x01 "$data"
direct_write "$phy_chipaddr" 0x00 "$cmd"
indirect_wait
}
mdio_read() {
local address="$1"
local offset="$2"
local bits="$3"
[ "$verbose" = 1 ] && printf "read: 0x%.2x:0x%.2x\n" "$address"
"$offset" >&2
if [ -n "$phy_chipaddr" ]; then
value=$(indirect_read "$address" "$offset")
else
value=$(direct_read "$address" "$offset")
fi
[ $? = 0 ] || echo "Read error: address=$1 offset=$2" >&2
if [ -z "$bits" ]; then
echo $value
else
_get_bits "$bits" "$value"
fi
}
mdio_write() {
local address="$1"
local offset="$2"
local bits="$3"
local value="$4"
if [ -n "$bits" ]; then
original="$(mdio_read "$address" "$offset")"
value="$(_set_bits "$original" "$bits" "$value")"
fi
[ -n "$verbose" -a -n "$no_write" ] && printf "no "
[ -n "$verbose" ] && printf "write: 0x%.2x:0x%.2x = %.4x\n" "$address"
"$offset" "$value" >&2
if [ -z "$no_write" ]; then
if [ -n "$phy_chipaddr" ]; then
indirect_write "$address" "$offset" "$value"
else
direct_write "$address" "$offset" "$value"
fi
[ $? = 0 ] || echo "Write error: address=$1 offset=$2 value=$3"
>&2
fi
}
# TODO: Remember and reset original page rather than 0x0001.
mdio_page_set() {
if [ -n "$phy_page" ]; then
phy_orig_page="$(mdio_read "$1" 0x16)"
mdio_write "$1" 0x16 "$phy_page"
fi
}
mdio_page_reset() {
[ -n "$phy_page" ] && mdio_write "$1" 0x16 "$(phy_orig_page)"
}
usage() {
echo "Get c22 register:"
echo " mdio --phy --address 0 --offset 0x00"
echo " mdio -P -a 0 -o 0x00"
echo "Set c22 register:"
echo " mdio --phy --address 0 --offset 0x00 --write 0x8000"
echo " mdio -P -a 0 -o 0x00 -w 0x8000"
echo "Note: Read the source."
exit 1
}
exec 3<>"$MDIO_CONTROL"
[ -n "$phy_addresses" -a -n "$phy_offset" ] || usage
for phy_address in $phy_addresses; do
[ -n "$phy_device" ] && phy_offset=$(( phy_offset | phy_device << 16 |
0x40000000 ))
mdio_page_set "$phy_address"
if [ -n "$phy_value" ]; then
mdio_write "$phy_address" "$phy_offset" "$phy_bits" "$phy_value"
else
mdio_read "$phy_address" "$phy_offset" "$phy_bits"
fi
mdio_page_reset "$phy_address"
done