blob: c9da01baf3192f8f2e615edf025f6328c8e26967 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "rtl8211f.h"
#include <ddk/debug.h>
#include <ddk/platform-defs.h>
#include <fbl/unique_ptr.h>
#include <stdio.h>
#include <string.h>
#include <zircon/compiler.h>
#include <zircon/types.h>
#include "mdio-regs.h"
namespace phy {
zx_status_t PhyDevice::ConfigPhy(const uint8_t mac[MAC_ARRAY_LENGTH]) {
uint32_t val;
// WOL reset.
eth_mac_.MdioWrite(MII_EPAGSR, 0xd40);
eth_mac_.MdioWrite(22, 0x20);
eth_mac_.MdioWrite(MII_EPAGSR, 0);
eth_mac_.MdioWrite(MII_EPAGSR, 0xd8c);
eth_mac_.MdioWrite(16, (mac[1] << 8) | mac[0]);
eth_mac_.MdioWrite(17, (mac[3] << 8) | mac[2]);
eth_mac_.MdioWrite(18, (mac[5] << 8) | mac[4]);
eth_mac_.MdioWrite(MII_EPAGSR, 0);
eth_mac_.MdioWrite(MII_EPAGSR, 0xd8a);
eth_mac_.MdioWrite(17, 0x9fff);
eth_mac_.MdioWrite(MII_EPAGSR, 0);
eth_mac_.MdioWrite(MII_EPAGSR, 0xd8a);
eth_mac_.MdioWrite(16, 0x1000);
eth_mac_.MdioWrite(MII_EPAGSR, 0);
eth_mac_.MdioWrite(MII_EPAGSR, 0xd80);
eth_mac_.MdioWrite(16, 0x3000);
eth_mac_.MdioWrite(17, 0x0020);
eth_mac_.MdioWrite(18, 0x03c0);
eth_mac_.MdioWrite(19, 0x0000);
eth_mac_.MdioWrite(20, 0x0000);
eth_mac_.MdioWrite(21, 0x0000);
eth_mac_.MdioWrite(22, 0x0000);
eth_mac_.MdioWrite(23, 0x0000);
eth_mac_.MdioWrite(MII_EPAGSR, 0);
eth_mac_.MdioWrite(MII_EPAGSR, 0xd8a);
eth_mac_.MdioWrite(19, 0x1002);
eth_mac_.MdioWrite(MII_EPAGSR, 0);
// Fix txdelay issuee for rtl8211. When a hw reset is performed
// on the phy, it defaults to having an extra delay in the TXD path.
// Since we reset the phy, this needs to be corrected.
eth_mac_.MdioWrite(MII_EPAGSR, 0xd08);
eth_mac_.MdioRead(0x11, &val);
val &= ~0x100;
eth_mac_.MdioWrite(0x11, val);
eth_mac_.MdioWrite(MII_EPAGSR, 0x00);
// Enable GigE advertisement.
eth_mac_.MdioWrite(MII_GBCR, 1 << 9);
// Restart advertisements.
eth_mac_.MdioRead(MII_BMCR, &val);
val |= BMCR_ANENABLE | BMCR_ANRESTART;
val &= ~BMCR_ISOLATE;
eth_mac_.MdioWrite(MII_BMCR, val);
return ZX_OK;
}
void PhyDevice::DdkUnbind() {
DdkRemove();
}
void PhyDevice::DdkRelease() {
delete this;
}
zx_status_t PhyDevice::Create(zx_device_t* device) {
fbl::AllocChecker ac;
auto phy_device = fbl::make_unique_checked<PhyDevice>(&ac, device);
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
// Get ETH_MAC protocol.
if (!phy_device->eth_mac_.is_valid()) {
zxlogf(ERROR, "aml-dwmac: could not obtain ETH_BOARD protocol\n");
return ZX_ERR_NO_RESOURCES;
}
zx_status_t status = phy_device->DdkAdd("phy_null_device", DEVICE_ADD_NON_BINDABLE);
if (status != ZX_OK) {
zxlogf(ERROR, "dwmac: Could not create phy device: %d\n", status);
return status;
}
// devmgr now owns device.
auto* dev = phy_device.release();
eth_mac_callbacks_t cb;
cb.config_phy = [](void* ctx, const uint8_t* mac) {
return static_cast<PhyDevice*>(ctx)->ConfigPhy(mac);
};
cb.ctx = dev;
dev->eth_mac_.RegisterCallbacks(&cb);
return status;
}
} // namespace phy
extern "C" zx_status_t rtl8211f_bind(void* ctx, zx_device_t* device) {
return phy::PhyDevice::Create(device);
}