// 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 <fuchsia/hardware/ethernet/c/banjo.h>
#include <lib/ddk/binding_driver.h>
#include <lib/ddk/debug.h>
#include <lib/ddk/driver.h>
#include <lib/ddk/metadata.h>
#include <lib/ddk/platform-defs.h>
#include <lib/device-protocol/i2c-channel.h>
#include <stdio.h>
#include <string.h>
#include <zircon/compiler.h>

#include <iterator>

#include <fbl/algorithm.h>
#include <fbl/alloc_checker.h>
#include <fbl/auto_lock.h>
#include <soc/aml-s912/s912-hw.h>

#include "aml-regs.h"

namespace eth {

#define MCU_I2C_REG_BOOT_EN_WOL 0x21
#define MCU_I2C_REG_BOOT_EN_WOL_RESET_ENABLE 0x03

void AmlEthernet::ResetPhy(ResetPhyCompleter::Sync& completer) {
  const auto& gpio_reset = gpios_[PHY_RESET];
  if (gpio_reset.is_valid()) {
    {
      fidl::WireResult result = gpio_reset->Write(0);
      if (!result.ok()) {
        zxlogf(ERROR, "Failed to send Write request to reset gpio: %s", result.status_string());
        completer.ReplyError(result.status());
        return;
      }
      if (result->is_error()) {
        zxlogf(ERROR, "Failed to write 0 to reset gpio: %s",
               zx_status_get_string(result->error_value()));
        completer.ReplyError(result->error_value());
        return;
      }
    }
    zx_nanosleep(zx_deadline_after(ZX_MSEC(100)));
    {
      fidl::WireResult result = gpio_reset->Write(1);
      if (!result.ok()) {
        zxlogf(ERROR, "Failed to send Write request to reset gpio: %s", result.status_string());
        completer.ReplyError(result.status());
        return;
      }
      if (result->is_error()) {
        zxlogf(ERROR, "Failed to write 1 to reset gpio: %s",
               zx_status_get_string(result->error_value()));
        completer.ReplyError(result->error_value());
        return;
      }
    }
    zx_nanosleep(zx_deadline_after(ZX_MSEC(100)));
  }
  completer.ReplySuccess();
}

zx_status_t AmlEthernet::InitPdev() {
  pdev_ = ddk::PDevFidl::FromFragment(parent());
  if (!pdev_.is_valid()) {
    zxlogf(ERROR, "Could not get PDEV protocol");
    return ZX_ERR_NO_RESOURCES;
  }

  // Not needed on vim3.
  i2c_ = ddk::I2cChannel(parent(), "i2c");

  // Reset is optional.
  zx::result gpio_reset = DdkConnectFragmentFidlProtocol<fuchsia_hardware_gpio::Service::Device>(
      parent(), "gpio-reset");
  if (gpio_reset.is_ok()) {
    gpios_[PHY_RESET].Bind(std::move(gpio_reset.value()));
  }

  const char* kInterruptGpioFragmentName = "gpio-int";
  zx::result gpio_int = DdkConnectFragmentFidlProtocol<fuchsia_hardware_gpio::Service::Device>(
      parent(), kInterruptGpioFragmentName);
  if (gpio_int.is_error()) {
    zxlogf(ERROR, "Failed to get GPIO protocol from fragment %s: %s", kInterruptGpioFragmentName,
           gpio_int.status_string());
    return ZX_ERR_NO_RESOURCES;
  }
  gpios_[PHY_INTR].Bind(std::move(gpio_int.value()));

  // Map amlogic peripheral control registers.
  zx_status_t status = pdev_.MapMmio(MMIO_PERIPH, &periph_mmio_);
  if (status != ZX_OK) {
    zxlogf(ERROR, "aml-dwmac: could not map periph mmio: %d", 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", status);
    return status;
  }

  return status;
}

zx_status_t AmlEthernet::Bind() {
  // Set reset line to output if implemented
  const auto& gpio_reset = gpios_[PHY_RESET];
  if (gpio_reset.is_valid()) {
    fidl::WireResult result = gpio_reset->ConfigOut(0);
    if (!result.ok()) {
      zxlogf(ERROR, "Failed to send ConfigOut request to reset gpio: %s", result.status_string());
      return result.status();
    }
    if (result->is_error()) {
      zxlogf(ERROR, "Failed to configure reset gpio to output: %s",
             _zx_status_get_string(result->error_value()));
      return result->error_value();
    }
  }

  pdev_board_info_t board;
  bool is_vim3 = false;
  zx_status_t status = pdev_.GetBoardInfo(&board);

  if (status != ZX_OK || board.pid != PDEV_PID_AV400) {
    // Initialize AMLogic peripheral registers associated with dwmac.
    // Sorry about the magic...rtfm
    periph_mmio_->Write32(0x1621, PER_ETH_REG0);
    if (status == ZX_OK) {
      is_vim3 = ((board.vid == PDEV_VID_KHADAS) && (board.pid == PDEV_PID_VIM3));
    }

    if (!is_vim3) {
      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);
  }

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

  auto* dispatcher = fdf::Dispatcher::GetCurrent()->async_dispatcher();
  outgoing_ = component::OutgoingDirectory(dispatcher);

  fuchsia_hardware_ethernet_board::Service::InstanceHandler handler({
      .device = bindings_.CreateHandler(this, dispatcher, fidl::kIgnoreBindingClosure),
  });
  auto result = outgoing_->AddService<fuchsia_hardware_ethernet_board::Service>(std::move(handler));
  if (result.is_error()) {
    zxlogf(ERROR, "Failed to add service to the outgoing directory");
    return result.status_value();
  }

  auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
  if (endpoints.is_error()) {
    return endpoints.status_value();
  }

  result = outgoing_->Serve(std::move(endpoints->server));
  if (result.is_error()) {
    zxlogf(ERROR, "Failed to serve the outgoing directory");
    return result.status_value();
  }

  std::array offers = {
      fuchsia_hardware_ethernet_board::Service::Name,
  };

  return DdkAdd(ddk::DeviceAddArgs("aml-ethernet")
                    .set_fidl_service_offers(offers)
                    .set_outgoing_dir(endpoints->client.TakeChannel()));
}

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

zx_status_t AmlEthernet::Create(void* ctx, zx_device_t* parent) {
  zxlogf(INFO, "aml-ethernet: adding driver");
  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) {
    zxlogf(ERROR, "aml-ethernet: failed to init platform device");
    return status;
  }

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

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

  return ZX_OK;
}

static constexpr 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(aml_eth, eth::driver_ops, "aml-ethernet", "0.1");
