// 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 "aml-ethernet.h"
#include "aml-regs.h"
#include <ddk/binding.h>
#include <ddk/debug.h>
#include <ddk/driver.h>
#include <ddk/metadata.h>
#include <ddk/platform-defs.h>
#include <ddk/protocol/i2c-lib.h>
#include <ddk/protocol/composite.h>
#include <ddk/protocol/ethernet.h>
#include <ddk/protocol/platform/device.h>
#include <ddk/protocol/platform-device-lib.h>
#include <fbl/algorithm.h>
#include <fbl/auto_call.h>
#include <fbl/auto_lock.h>
#include <fbl/unique_ptr.h>
#include <hw/reg.h>
#include <soc/aml-s912/s912-hw.h>
#include <stdio.h>
#include <string.h>
#include <zircon/compiler.h>

namespace eth {

#define MCU_I2C_REG_BOOT_EN_WOL 0x21
#define MCU_I2C_REG_BOOT_EN_WOL_RESET_ENABLE 0x03

zx_status_t AmlEthernet::EthBoardResetPhy() {
    gpios_[PHY_RESET].Write(0);
    zx_nanosleep(zx_deadline_after(ZX_MSEC(100)));
    gpios_[PHY_RESET].Write(1);
    zx_nanosleep(zx_deadline_after(ZX_MSEC(100)));
    return ZX_OK;
}

zx_status_t AmlEthernet::InitPdev() {
    composite_protocol_t composite;

    auto status = device_get_protocol(parent(), ZX_PROTOCOL_COMPOSITE, &composite);
    if (status != ZX_OK) {
        zxlogf(ERROR, "Could not get composite protocol\n");
        return status;
    }

    zx_device_t* components[COMPONENT_COUNT];
    size_t actual;
    composite_get_components(&composite, components, fbl::count_of(components), &actual);
    if (actual != fbl::count_of(components)) {
        zxlogf(ERROR, "could not get components\n");
        return ZX_ERR_NOT_SUPPORTED;
    }

    pdev_protocol_t pdev;
    status = device_get_protocol(components[COMPONENT_PDEV], ZX_PROTOCOL_PDEV, &pdev);
    if (status !=  ZX_OK) {
        zxlogf(ERROR, "Could not get PDEV protocol\n");
        return status;
    }
    pdev_ = &pdev;

    i2c_protocol_t i2c;
    status = device_get_protocol(components[COMPONENT_I2C], ZX_PROTOCOL_I2C, &i2c);
    if (status !=  ZX_OK) {
        zxlogf(ERROR, "Could not get I2C protocol\n");
        return status;
    }
    i2c_ = &i2c;

    gpio_protocol_t gpio;
    status = device_get_protocol(components[COMPONENT_RESET_GPIO], ZX_PROTOCOL_GPIO, &gpio);
    if (status !=  ZX_OK) {
        zxlogf(ERROR, "Could not get GPIO protocol\n");
        return status;
    }
    gpios_[PHY_RESET] = &gpio;

    status = device_get_protocol(components[COMPONENT_INTR_GPIO], ZX_PROTOCOL_GPIO, &gpio);
    if (status !=  ZX_OK) {
        zxlogf(ERROR, "Could not get GPIO protocol\n");
        return status;
    }
    gpios_[PHY_INTR] = &gpio;

    // Map amlogic peripheral control registers.
    status = pdev_.MapMmio(MMIO_PERIPH, &periph_mmio_);
    if (status != ZX_OK) {
        zxlogf(ERROR, "aml-dwmac: could not map periph mmio: %d\n", status);
        return status;
    }

    // Map HHI regs (clocks and power domains).
    status = pdev_.MapMmio(MMIO_HHI, &hhi_mmio_);
    if (status != ZX_OK) {
        zxlogf(ERROR, "aml-dwmac: could not map hiu mmio: %d\n", status);
        return status;
    }

    return status;
}

zx_status_t AmlEthernet::Bind() {
    // Set reset line to output
    gpios_[PHY_RESET].ConfigOut(0);

    // Initialize AMLogic peripheral registers associated with dwmac.
    //Sorry about the magic...rtfm
    periph_mmio_->Write32(0x1621, PER_ETH_REG0);
    periph_mmio_->Write32(0x20000, PER_ETH_REG1);

    periph_mmio_->Write32(REG2_ETH_REG2_REVERSED | REG2_INTERNAL_PHY_ID, PER_ETH_REG2);

    periph_mmio_->Write32(REG3_CLK_IN_EN | REG3_ETH_REG3_19_RESVERD |
                              REG3_CFG_PHY_ADDR | REG3_CFG_MODE |
                              REG3_CFG_EN_HIGH | REG3_ETH_REG3_2_RESERVED,
                          PER_ETH_REG3);

    // Enable clocks and power domain for dwmac
    hhi_mmio_->SetBits32(1 << 3, HHI_GCLK_MPEG1);
    hhi_mmio_->ClearBits32((1 << 3) | (1 << 2), HHI_MEM_PD_REG0);

    // WOL reset enable to MCU
    uint8_t write_buf[2] = {MCU_I2C_REG_BOOT_EN_WOL, MCU_I2C_REG_BOOT_EN_WOL_RESET_ENABLE};
    zx_status_t status = i2c_.WriteSync(write_buf, sizeof(write_buf));
    if (status) {
        zxlogf(ERROR, "aml-ethernet: WOL reset enable to MCU failed: %d\n", status);
        return status;
    }

    // Populate board specific information
    eth_dev_metadata_t mac_info;
    size_t actual;
    status = device_get_metadata(parent(), DEVICE_METADATA_ETH_MAC_DEVICE, &mac_info,
                                 sizeof(eth_dev_metadata_t), &actual);
    if (status != ZX_OK || actual != sizeof(eth_dev_metadata_t)) {
        zxlogf(ERROR, "aml-ethernet: Could not get MAC metadata %d\n", status);
        return status;
    }

    zx_device_prop_t props[] = {
        {BIND_PLATFORM_DEV_VID, 0, mac_info.vid},
        {BIND_PLATFORM_DEV_DID, 0, mac_info.did},
    };

    return DdkAdd("aml-ethernet", 0, props, fbl::count_of(props));
}

void AmlEthernet::DdkUnbind() {
    DdkRemove();
}

void AmlEthernet::DdkRelease() {
    delete this;
}

zx_status_t AmlEthernet::Create(void* ctx, zx_device_t* parent) {
    fbl::AllocChecker ac;
    auto eth_device = fbl::make_unique_checked<AmlEthernet>(&ac, parent);
    if (!ac.check()) {
        return ZX_ERR_NO_MEMORY;
    }

    zx_status_t status = eth_device->InitPdev();
    if (status != ZX_OK) {
        return status;
    }

    status = eth_device->Bind();
    if (status != ZX_OK) {
        zxlogf(ERROR, "aml-ethernet driver failed to get added: %d\n", status);
        return status;
    } else {
        zxlogf(INFO, "aml-ethernet driver added\n");
    }

    // eth_device intentionally leaked as it is now held by DevMgr
    __UNUSED auto ptr = eth_device.release();

    return ZX_OK;
}

static zx_driver_ops_t driver_ops = [](){
    zx_driver_ops_t ops = {};
    ops.version = DRIVER_OPS_VERSION;
    ops.bind = AmlEthernet::Create;
    return ops;
}();

} // namespace eth

// clang-format off
ZIRCON_DRIVER_BEGIN(aml_eth, eth::driver_ops, "aml-ethernet", "0.1", 4)
    BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_COMPOSITE),
    BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_AMLOGIC),
    BI_ABORT_IF(NE, BIND_PLATFORM_DEV_PID, PDEV_PID_AMLOGIC_S912),
    BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_DID, PDEV_DID_AMLOGIC_ETH),
ZIRCON_DRIVER_END(aml_eth)
