/*
* Copyright (c) 2023-2028, SpaceTouch Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date          Author      Notes
* 2023-07-18    zhixiongl       the first version
*/
// #include "platform.h"
// #include "rtconfig.h"

#include "board.h"

#if defined(USING_USBD)

#include <stdio.h>
#include <stdarg.h>
#include "hal_log.h"

#include "hal_usbd_reg.h"
#include "hal_usbd_init.h"
#include "hal_usbd.h"

#include "hal_gpio.h"
#include "hal_common.h"
#include "hal_cmu.h"
#include "board.h"

// #include <rtdevice.h>
// #include <drv_usbd.h>

/**
* @brief
* @details
* @param[in]
* @return
* @note         None
*/
void usb_clock_init(void)
{
    DEV_RMU->RSTEN0 &= ~DEV_RMU_RSTEN0_USB;
    DEV_RMU->RSTEN0 |= DEV_RMU_RSTEN0_USB;
    DEV_CMU->CLKEN0 |= DEV_CMU_CLKEN0_USB;
    DEV_CMU->USBCLK = 0x01 | (0x01 << 2);
}

/**
* @brief
* @details
* @param[in]
* @return
* @note         None
*/
void usb_select_clockcource(uint8_t clk_sel)
{
    uint8_t core_sel = 0;
    core_sel = usb_read_reg((uint32_t *)USB_PHY_CTRL0, 0, 8);

    switch (clk_sel)
    {
    case 0 :
        usb_write_reg((core_sel & (~0x08)), (uint32_t *)USB_PHY_CTRL0, 0, 8);
        break;

    case 1:
        usb_write_reg((core_sel | (0x08)), (uint32_t *)USB_PHY_CTRL0, 0, 8);
        break;

    default:
        break;
    }
}

/**
* @brief        select usb osc clock source
* @details
* @param[in]
* @return
* @note         None
*/
void usb_select_osc_clockcource(uint16_t clk_sel)
{
    uint16_t core_sel = 0;
    core_sel = usb_read_reg((uint32_t *)USB_PLL_CTRL, 2, 16);

    switch (clk_sel)
    {
    case 0 :
        usb_write_reg((core_sel & (~(0x01 << 12))), (uint32_t *)USB_PLL_CTRL, 2, 16);
        break;

    case 1:
        usb_write_reg((core_sel | (0x01 << 12)), (uint32_t *)USB_PLL_CTRL, 2, 16);
        break;

    default:
        break;
    }
}

/**
* @brief
* @details
* @param[in]
* @return
* @note         None
*/
void usb_set_rc_trim(uint16_t trim)
{
    uint16_t osc_trim = 0;
    osc_trim = usb_read_reg((uint32_t *)USB_PLL_CTRL, 2, 16);
    osc_trim &= ~(0x7f);
    usb_write_reg((osc_trim | trim), (uint32_t *)USB_PLL_CTRL, 2, 16);
}
/**
* @brief
* @details
* @param[in]
* @return
* @note         None
*/
void usb_select_pll_divider_signal(uint16_t source)
{
    uint16_t signal = 0;
    signal = usb_read_reg((uint32_t *)USB_PHY_CTRL0, 0, 16);

    switch (source)
    {
    case 0 :
        usb_write_reg((signal & (~(0x01 << 7))), (uint32_t *)USB_PHY_CTRL0, 0, 16);
        break;

    case 1:
        usb_write_reg((signal | (0x01 << 7)), (uint32_t *)USB_PHY_CTRL0, 0, 16);
        break;

    default:
        break;
    }
}
/**
* @brief
* @details
* @param[in]
* @return
* @note         None
*/
void usb_set_pll_trim(uint16_t trim)
{
    uint16_t osc_trim = 0;
    osc_trim = usb_read_reg((uint32_t *)USB_PHY_CTRL0, 2, 16);
    osc_trim &= ~(0x1ff);
    usb_write_reg((osc_trim | trim), (uint32_t *)USB_PHY_CTRL0, 2, 16);
}

/**
* @brief          set phy power on or off
* @details
* @param[in]
* @return
* @note         None
*/
void usb_phy_power(uint8_t power)
{
    uint8_t power_status = 0;
    power_status = usb_read_reg((uint32_t *)USB_PHY_CTRL0, 0, 8);

    switch (power)
    {
    case 0 :
        usb_write_reg((power_status & (~0x02)), (uint32_t *)USB_PHY_CTRL0, 0, 8);
        break;

    case 1:
        usb_write_reg((power_status | (0x02)), (uint32_t *)USB_PHY_CTRL0, 0, 8);
        break;

    default:
        break;
    }
}

/**
* @brief        pll enable
* @details
* @param[in]
* @return
* @note         None
*/
void usb_phy_pll(uint8_t pll_enable)
{
    uint8_t pll_enabled = 0;
    pll_enabled = usb_read_reg((uint32_t *)USB_PHY_CTRL0, 0, 8);

    switch (pll_enable)
    {
    case 0 :
        usb_write_reg((pll_enabled & (~0x04)), (uint32_t *)USB_PHY_CTRL0, 0, 8);
        break;

    case 1:
        usb_write_reg((pll_enabled | (0x04)), (uint32_t *)USB_PHY_CTRL0, 0, 8);
        break;

    default:
        break;
    }
}

/**
* @brief        phy work mode
* @details
* @param[in]
* @return
* @note         None
*/
void usb_phy_work_mode(uint8_t phy_work)
{
    uint8_t phy_work_state = 0;
    phy_work_state = usb_read_reg((uint32_t *)USB_PHY_CTRL0, 0, 8);

    switch (phy_work)
    {
    case 0 :
        usb_write_reg((phy_work_state & (~0x01)), (uint32_t *)USB_PHY_CTRL0, 0, 8);
        break;

    case 1:
        usb_write_reg((phy_work_state | (0x01)), (uint32_t *)USB_PHY_CTRL0, 0, 8);
        break;

    default:
        break;
    }
}

/**
* @brief          select pll clock source
* @details
* @param[in]
* @return
* @note         None
*/
void usb_pll_select_clockcource(uint32_t clk_sel)
{
    uint32_t core_sel = 0;
    core_sel = usb_read_reg((uint32_t *)USB_PLL_CTRL, 0, 32);

    switch (clk_sel)
    {
    case 0 :
        usb_write_reg((core_sel & (~0x10000000)), (uint32_t *)USB_PLL_CTRL, 0, 32);
        break;

    case 1:
        usb_write_reg((core_sel | (0x10000000)), (uint32_t *)USB_PLL_CTRL, 0, 32);
        break;

    default:
        break;
    }
}

/**
* @brief
* @details
* @param[in]
* @return
* @note         None
*/
void usb_update_init(int hsfs)
{
    usb_clock_init();
    HAL_USBD_LOG("usb_clock_init\n");
#ifndef USE_USB_RC
    /* lzx&N 如果不使用RC时钟 */
    usb_select_clockcource(1);      //PLL时钟选择  1: CLK_12MHz   0: inner osc
#else
    /* lzx&N 如果使用RC时钟 */
    usb_select_clockcource(0);      //PLL时钟选择  1: CLK_12MHz   0: inner osc
//  uint32_t reg = *(volatile uint32_t *)(0x20006000+0x0c);
//  reg &= ~(0x7f << 16);
//  reg |= (55 << 16) | (1 << 28);
//  *(volatile uint32_t *)(0x20006000+0x0c) = reg;
    usb_select_osc_clockcource(1);
    usb_set_rc_trim(55);
    usb_select_pll_divider_signal(1);
    usb_set_pll_trim(55);
//  *(volatile uint32_t *)(0x20006000) |= (1<<7) | (0 << 4);
//  reg = *(volatile uint32_t *)(0x20006000);
//  reg &= ~(0x1ff << 16);
//  reg |= (52 << 16);
//  *(volatile uint32_t *)(0x20006000) = reg;
#endif
    usb_phy_power(1);        //使能PHY power
    usb_phy_pll(1);          //强制使能phy内部PLL
    usb_phy_work_mode(0);    //phy working
//  __nds__plic_set_priority(IRQ_SOURCE_USB_MAC,2);

    if (hsfs == USB_HS)
    {
        HAL_USBD_LOG("USB_HS\n");
        usb_write_power(REG_POWER_SOFT_CONN | REG_POWER_HS_ENAB);       //使能USB HS模式和软连接
    }
    else
    {
        HAL_USBD_LOG("USB_FS\n");
        usb_write_power(REG_POWER_SOFT_CONN);                           //使能USB FS模式和软连接
    }

    HAL_INTERRUPT_ENABLE(IRQ_SOURCE_USB_MAC);
    //HAL_INTERRUPT_DISABLE(IRQ_SOURCE_USB_MAC);
}
#endif

