/*
 * Copyright (c) 2024, sakumisu
 *
 * SPDX-License-Identifier: Apache-2.0
 */
#include "usbd_core.h"
#include "usbh_core.h"
#include "usb_dwc2_param.h"
#include "stm32f4xx.h"
#include "systick_conf.h"
#include "pin_ctrl.h"

#ifndef CONFIG_USB_DWC2_CUSTOM_PARAM

const struct dwc2_user_params param_pa11_pa12 = {
    .phy_type = DWC2_PHY_TYPE_PARAM_FS,
    .device_dma_enable = false,
    .device_dma_desc_enable = false,
    .device_rx_fifo_size = (320 - 16 - 16 - 16 - 16),
    .device_tx_fifo_size = {
        [0] = 16, // 64 byte
        [1] = 16, // 64 byte
        [2] = 16, // 64 byte
        [3] = 16, // 64 byte
        [4] = 0,
        [5] = 0,
        [6] = 0,
        [7] = 0,
        [8] = 0,
        [9] = 0,
        [10] = 0,
        [11] = 0,
        [12] = 0,
        [13] = 0,
        [14] = 0,
        [15] = 0 },
    .device_gccfg = ((1 << 16) | (1 << 21)), // fs: USB_OTG_GCCFG_PWRDWN | USB_OTG_GCCFG_NOVBUSSENS
    .total_fifo_size = 320 // 1280 byte
};

//0x01 (OUT)：承担所有下行大数据（UAC 音频流、Display 图像流、MSC 写 U 盘、CDC 收数据、Gamepad 震动反馈）。
//0x81 (IN)：承担所有上行大数据（MSC 读 U盘、CDC 发数据、所有 HID 设备的按键上报、Display 触摸/应答）。
//0x82 (IN)：承担所有上行微小数据（CDC 的状态中断 INT，UAC1/2 的时钟反馈 Feedback）。

const struct dwc2_user_params param_pb14_pb15 = {
#ifdef CONFIG_USB_HS
    .phy_type = DWC2_PHY_TYPE_PARAM_UTMI,
#else
    .phy_type = DWC2_PHY_TYPE_PARAM_FS,
#endif
#ifdef CONFIG_USB_DWC2_DMA_ENABLE
    .device_dma_enable = true,
#else
    .device_dma_enable = false,
#endif
    .device_dma_desc_enable = false,
    
    // 【RX FIFO 极致容量】：2048 字节，再大的 UAC 数据包也不怕
    .device_rx_fifo_size = 512, 
    
    // 【TX FIFO 集中分配】
    .device_tx_fifo_size = {
        [0] = 32,   // EP0: 128 Bytes
        [1] = 256,  // EP1 (0x81): 1536 Bytes，主数据通道的超级狂飙缓存！
        [2] = 32,   // EP2 (0x82): 128 Bytes，中断/反馈通道
        [3] = 16,   
        [4] = 16,
        [5] = 16,
        [6] = 0,
        [7] = 0,
        [8] = 0,
        [9] = 0,
        [10] = 0,
        [11] = 0,
        [12] = 0,
        [13] = 0,
        [14] = 0,
        [15] = 0 
    },

    .host_dma_desc_enable = false,
    .host_rx_fifo_size = 622,
    .host_nperio_tx_fifo_size = 128, 
    .host_perio_tx_fifo_size = 256,  
    .device_gccfg = ((1 << 16) | (1 << 21)), 
    .host_gccfg = ((1 << 16) | (1 << 21))    
};

#endif // CONFIG_USB_DWC2_CUSTOM_PARAM

typedef void (*usb_dwc2_irq)(uint8_t busid);

static usb_dwc2_irq g_usb_dwc2_irq[2];
static uint8_t g_usb_dwc2_busid[2] = { 0, 0 };

void usb_dc_low_level_init(uint8_t busid)
{
	g_usb_dwc2_busid[1] = busid;
    g_usb_dwc2_irq[1] = USBD_IRQHandler;
	
	/* 1. 开 USBOTG_HS 和 GPIOB 时钟 */
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_OTG_HS, ENABLE);

    /* 2. 【核心修复 1】硬件强制复位（清空 DWC2 底层 FIFO 内存泄露） */
    RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_OTG_HS, ENABLE);
    for(volatile int i=0; i<50000; i++); 
    RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_OTG_HS, DISABLE);
    for(volatile int i=0; i<50000; i++);

    /* 3. 配置 PB14/PB15 为 OTG_HS FS DP/DM */
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_OTG_HS_FS);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_OTG_HS_FS);
	
    /* 4. 【核心修复 2】重新开启中断！（因为 deinit 里把它关了） */
    // 优先级已经在 nvic_conf.c 中配置过了，这里直接 Enable 即可
    NVIC_EnableIRQ(OTG_HS_IRQn);

	USB_Power_Out_Ctrl(0); //0-关  1-开
	USB_Slave_Host_Ctrl(0); //0-从  1-主
}

void usb_hc_low_level_init(struct usbh_bus *bus)
{
	g_usb_dwc2_busid[1] = bus->hcd.hcd_id;
    g_usb_dwc2_irq[1] = USBH_IRQHandler;

    /* 开 USBOTG_HS 和 GPIOB 时钟 */
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_OTG_HS, ENABLE);

    /* 【核心修复 1】硬件强制复位 */
    RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_OTG_HS, ENABLE);
    for(volatile int i=0; i<50000; i++); 
    RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_OTG_HS, DISABLE);
    for(volatile int i=0; i<50000; i++);

    /* 配置 PB14/PB15 为 OTG_HS FS DP/DM */
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_OTG_HS_FS);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_OTG_HS_FS);
	
    /* 【核心修复 2】重新开启中断！ */
    NVIC_EnableIRQ(OTG_HS_IRQn);

	USB_Power_Out_Ctrl(1); //0-关  1-开
	USB_Slave_Host_Ctrl(1); //0-从  1-主
}

void usb_dc_low_level_deinit(uint8_t busid)
{
    /* 1. 【防 HardFault 核心】必须先彻底关闭并清除中断，再清空回调指针！ */
    NVIC_DisableIRQ(OTG_HS_IRQn);
    NVIC_ClearPendingIRQ(OTG_HS_IRQn);

    /* 2. 清空指针 */
	g_usb_dwc2_busid[1] = 0;
    g_usb_dwc2_irq[1] = NULL;

    /* 3. 关时钟和配置 GPIO */
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_OTG_HS, DISABLE);

    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; // 下拉
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    // 强行输出低电平
    GPIO_ResetBits(GPIOB, GPIO_Pin_14 | GPIO_Pin_15);
	
	USB_Power_Out_Ctrl(0); //0-关  1-开
	USB_Slave_Host_Ctrl(0); //0-从  1-主
}

void usb_hc_low_level_deinit(struct usbh_bus *bus)
{
    /* 1. 【防 HardFault 核心】必须先彻底关闭并清除中断！ */
    NVIC_DisableIRQ(OTG_HS_IRQn);
    NVIC_ClearPendingIRQ(OTG_HS_IRQn);

    /* 2. 清空指针 */
	g_usb_dwc2_busid[1] = 0;
    g_usb_dwc2_irq[1] = NULL;

    /* 3. 关时钟和配置 GPIO */
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_OTG_HS, DISABLE);

    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	USB_Power_Out_Ctrl(0); //0-关  1-开
	USB_Slave_Host_Ctrl(0); //0-从  1-主
}

#ifndef CONFIG_USB_DWC2_CUSTOM_PARAM
void dwc2_get_user_params(uint32_t reg_base, struct dwc2_user_params *params)
{
    if (reg_base == 0x40040000UL) { // USB_OTG_HS_PERIPH_BASE
        memcpy(params, &param_pb14_pb15, sizeof(struct dwc2_user_params));
    } else {
        memcpy(params, &param_pa11_pa12, sizeof(struct dwc2_user_params));
    }
#ifdef CONFIG_USB_DWC2_CUSTOM_FIFO
    struct usb_dwc2_user_fifo_config s_dwc2_fifo_config;

    dwc2_get_user_fifo_config(reg_base, &s_dwc2_fifo_config);

    params->device_rx_fifo_size = s_dwc2_fifo_config.device_rx_fifo_size;
    for (uint8_t i = 0; i < MAX_EPS_CHANNELS; i++)
    {
        params->device_tx_fifo_size[i] = s_dwc2_fifo_config.device_tx_fifo_size[i];
    }
#endif
}
#endif

extern uint32_t SystemCoreClock;

void usbd_dwc2_delay_ms(uint8_t ms)
{
    uint32_t count = SystemCoreClock / 1000 * ms;
    while (count--) {
        __asm volatile("nop");
    }
}

uint32_t usbd_dwc2_get_system_clock(void)
{
    return SystemCoreClock;
}

void OTG_FS_IRQHandler(void)
{
    if (g_usb_dwc2_irq[0] != NULL) {
        g_usb_dwc2_irq[0](g_usb_dwc2_busid[0]);
    }
}

void OTG_HS_IRQHandler(void)
{
    if (g_usb_dwc2_irq[1] != NULL) {
        g_usb_dwc2_irq[1](g_usb_dwc2_busid[1]);
    }
}

#ifdef CONFIG_USB_DCACHE_ENABLE
void usb_dcache_clean(uintptr_t addr, size_t size)
{
    SCB_CleanDCache_by_Addr((void *)addr, size);
}

void usb_dcache_invalidate(uintptr_t addr, size_t size)
{
    SCB_InvalidateDCache_by_Addr((void *)addr, size);
}

void usb_dcache_flush(uintptr_t addr, size_t size)
{
    SCB_CleanInvalidateDCache_by_Addr((void *)addr, size);
}
#endif
