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

Reply via email to