Subject: Re: Atheros 8035 PHY only works when at803x_config_init() is commented out

From: Florian Fainelli <[email-masked]>
Date: Thu, 09 Apr 2015 15:30:47 -0700

On 09/04/15 15:10, Mason wrote:
> Florian Fainelli wrote:
>> Mason wrote:
>>> Florian Fainelli wrote:
>>>> Quoting IEEE 802.3 section 2, paragraph 22.2.4.1:
>>>>
>>>> "Resetting a PHY is accomplished by setting bit 0.15 to a logic one.
>>>> This action shall set the status and control registers to their 
>>>> default states. As a consequence this action may change the internal 
>>>> state of the PHY and the state of the physical link associated with 
>>>> the PHY. This bit is self-clearing, and a PHY shall return a value
>>>> of one in bit 0.15 until the reset process is completed. A PHY is
>>>> not required to accept a write transaction to the control register 
>>>> until the reset process is completed, and writes to bits of the 
>>>> control register other than 0.15 may have no effect until the reset 
>>>> process is completed. The reset process shall be completed within
>>>> 0.5 s from the setting of bit 0.15"
>>>>
>>>> So even though this is not extremely specific about whether or not doing
>>>> a RMW instead of W is accepted, considering that this resets the PHY
>>>> internal state, and the fact that there is a lack of clarify on whether
>>>> setting any bits other than 15 is going to fall under the "A PHY is not
>>>> required to accept a write transaction to the control register until the
>>>> reset process is completed" statement, setting only this bit at least
>>>> guarantees that you are back into your reset defaults.
>>>>
>>>> As Daniel suggested, I would be looking for undocumented/proprietary
>>>> registers for reasons as to why your PHY is not working, in particular
>>>> (RG)MII tuning.
>>>
>>> Am I the only having problems with the AR8035? :-(
>>>
>>> The standard driver works for everyone but me? 
>>>
>>> Did you take a look at the data sheet? Do you understand the
>>> difference between "Hardware Reset" and "Software Reset"?
>>
>> I did not.
> 
> If I understand your quote from the standard correctly,
> then the behavior documented in the data sheet looks
> very non-compliant to my untrained eye.
> 
>>> Also, why do you say the PHY is not working? When I apply the
>>> patch I proposed, it doesn't malfunction.
>>
>> There are no BMCR registers that would affect directly the passing of
>> unicast or broadcast traffic with distinction, which is how you
>> originally reported the problem, or maybe that was a bad description of
>> the issue?
> 
> I didn't say anything about unicast vs broadcast.
> 
> When I run the unpatched code, it looks like the PHY negotiates
> only 10 Mbps Half-duplex, then DHCP appears to succeed (IIUC
> only the very first packets are broadcast), and then the system
> hangs trying to mount the root filesystem over NFS.

So maybe you can make sure that your driver properly advertises all the
supported modes by your PHY, for instance, drivers/net/phy/bcm7xxx.c
calls genphy_config_aneg() to make sure that all modes are advertised
(the PHY does not advertise half-duplex modes by default).

> 
> I actually left it running over lunch break, and according
> to the kernel's time stamps, the system seems to have managed
> to mount the root file system after 2000+ seconds.

Ah, so it's doing something after all.

> 
>> Have you checked the Ethernet MAC MIB counters to see if there are any
>> errors reported differently from the working case to the non-working
>> case? What about your link partner, what does it looks like on its end
>> when it does not work?
> 
> Should I use ethtool for this?

Yes. Which might be difficult since you depend on networking to mount
your rootfs, you should probably use an initramfs so you need NFS root
to work.

> 
> Or do it directly with kernel code? (If so which API?)
> 
> The catch is that I need the network to get a running system.
> No network, no root file system.
> 
> Maybe I need to write the kernel to non-volatile storage.
> 
> 
> Going on a wild goose hunt...
> 
> Somewhat related discussion
> https://community.freescale.com/thread/289362
> 
> Let me check how u-boot handles the AR8035.
> http://git.denx.de/?p=u-boot.git;a=blob;f=drivers/net/phy/atheros.c
> 
> static int ar8035_config(struct phy_device *phydev)
> {
> 	int regval;
> 
> 	phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x0007);
> 	phy_write(phydev, MDIO_DEVAD_NONE, 0xe, 0x8016);
> 	phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x4007);
> 	regval = phy_read(phydev, MDIO_DEVAD_NONE, 0xe);
> 	phy_write(phydev, MDIO_DEVAD_NONE, 0xe, (regval|0x0018));
> 
> 	phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05);
> 	regval = phy_read(phydev, MDIO_DEVAD_NONE, 0x1e);
> 	phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, (regval|0x0100));
> 
> 	phydev->supported = phydev->drv->features;
> 
> 	return 0;
> }
> 
> Data sheet states:
> Register 0xd = "MMD Access Control". 
> Register 0xe = "MMD Access Control Data".
> 
> MMD register access:
> See detail in register description
> example: Write 0x8000 to Register 0 of MMD3
> 1. Write 0x3 to register 0xD: 
> 0xD=0x0003;(function= address; set the device address)
> 2. Write 0x0 to register 0xE: 0xE=0x0; (set the register offset address)
> 3. Write 0x4003 to register 
> 0xD:0xD=0x4003;(function=data; keep the device address)
> 4. Read register 0xE:0xE==(data from register 0x0 of MMD3)
> 5. Write 0x8000 to register 0xE 
> :0xE=0x8000(write 0x8000 to register 0x0 of MMD3)
> Please Note:Read operation please refers to process 1 ~ 4
> 
> Important note:
> CLK_25M default outputs 25MHz, can be configured to
> 50MHz, 62.5MHz, or 125MHz by register MMD7 8016[4:3].
> 
> Ah yes, there it is on page 58:
> Device address = 7, address offset = 0x8016 (Hex)
> 4:3 Select_clk125m
> CLK_25M output clock select
> 00=25M
> 01=50M
> 10=62.5M
> 11=125M
> 
> 
> So...
> 
> 	phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x0007);
> 	phy_write(phydev, MDIO_DEVAD_NONE, 0xe, 0x8016);
> 	phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x4007);
> 	regval = phy_read(phydev, MDIO_DEVAD_NONE, 0xe);
> 	phy_write(phydev, MDIO_DEVAD_NONE, 0xe, (regval|0x0018));
> 
> R[0xd] = 0x0007  ; select MMD7
> R[0xe] = 0x8016  ; offset 0x8016, so 
> R[0xd] = 0x4007  ; select "data, no post increment" for MMD7
> then we read the current value of MMD7/offset=0x8016
> and set bits 3 and 4 on top of that => 125 MHz clock
> 
> HW reset val = 0
> SW reset val = retain previous value
> so the reset in Linux shouldn't affect this...
> 
> 
> 	phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05);
> 	regval = phy_read(phydev, MDIO_DEVAD_NONE, 0x1e);
> 	phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, (regval|0x0100));
> 
> set debug port offset to 5 (DR5)
> read current value
> set bit 8 (rgmii_tx_clk_dly)
> 
> Rgmii tx clock delay control bit:
> 1 = rgmii tx clock delay enable
> 0 = rgmii tx clock delay disable.
> 
> AFAICT, the Linux code doesn't RMW, it just blindly writes
> AT803X_DEBUG_RGMII_TX_CLK_DLY. Dunno if it makes any difference...
> 
> Meh, I'm still grasping at straws...
> 
> Regards.
> 

-- 
Florian