First pads are being configured for use by the FPGA. Then CPU loads usbserial bitstream. Finally it reenables clocks, sets up USB PID and waits for device to enumerate. Also disable software resets in used clocks. Signed-off-by: Michal Sieron <msieron@antmicro.com>
152 lines
3.4 KiB
C
152 lines
3.4 KiB
C
/*
|
|
* Copyright (c) 2021 Antmicro <www.antmicro.com>
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <zephyr/device.h>
|
|
#include <zephyr/drivers/fpga.h>
|
|
#include "fpga_eos_s3.h"
|
|
|
|
void eos_s3_fpga_enable_clk(void)
|
|
{
|
|
CRU->C16_CLK_GATE = C16_CLK_GATE_PATH_0_ON;
|
|
CRU->C21_CLK_GATE = C21_CLK_GATE_PATH_0_ON;
|
|
CRU->C09_CLK_GATE = C09_CLK_GATE_PATH_1_ON | C09_CLK_GATE_PATH_2_ON;
|
|
CRU->C02_CLK_GATE = C02_CLK_GATE_PATH_1_ON;
|
|
}
|
|
|
|
void eos_s3_fpga_disable_clk(void)
|
|
{
|
|
CRU->C16_CLK_GATE = C16_CLK_GATE_PATH_0_OFF;
|
|
CRU->C21_CLK_GATE = C21_CLK_GATE_PATH_0_OFF;
|
|
CRU->C09_CLK_GATE = C09_CLK_GATE_PATH_1_OFF | C09_CLK_GATE_PATH_2_OFF;
|
|
CRU->C02_CLK_GATE = C02_CLK_GATE_PATH_1_OFF;
|
|
}
|
|
|
|
struct quickfeather_fpga_data {
|
|
char *FPGA_info;
|
|
};
|
|
|
|
static enum FPGA_status eos_s3_fpga_get_status(const struct device *dev)
|
|
{
|
|
ARG_UNUSED(dev);
|
|
|
|
if (PMU->FB_STATUS == FPGA_STATUS_ACTIVE) {
|
|
return FPGA_STATUS_ACTIVE;
|
|
} else
|
|
return FPGA_STATUS_INACTIVE;
|
|
}
|
|
|
|
static const char *eos_s3_fpga_get_info(const struct device *dev)
|
|
{
|
|
struct quickfeather_fpga_data *data = dev->data;
|
|
|
|
return data->FPGA_info;
|
|
}
|
|
|
|
static int eos_s3_fpga_on(const struct device *dev)
|
|
{
|
|
if (eos_s3_fpga_get_status(dev) == FPGA_STATUS_ACTIVE) {
|
|
return 0;
|
|
}
|
|
|
|
/* wake up the FPGA power domain */
|
|
PMU->FFE_FB_PF_SW_WU = PMU_FFE_FB_PF_SW_WU_FB_WU;
|
|
while (PMU->FFE_FB_PF_SW_WU == PMU_FFE_FB_PF_SW_WU_FB_WU) {
|
|
/* The register will clear itself if the FPGA starts */
|
|
};
|
|
|
|
eos_s3_fpga_enable_clk();
|
|
|
|
/* enable FPGA programming */
|
|
PMU->GEN_PURPOSE_0 = FB_CFG_ENABLE;
|
|
PIF->CFG_CTL = CFG_CTL_LOAD_ENABLE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int eos_s3_fpga_off(const struct device *dev)
|
|
{
|
|
if (eos_s3_fpga_get_status(dev) == FPGA_STATUS_INACTIVE) {
|
|
return 0;
|
|
}
|
|
|
|
PMU->FB_PWR_MODE_CFG = PMU_FB_PWR_MODE_CFG_FB_SD;
|
|
PMU->FFE_FB_PF_SW_PD = PMU_FFE_FB_PF_SW_PD_FB_PD;
|
|
|
|
eos_s3_fpga_disable_clk();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int eos_s3_fpga_reset(const struct device *dev)
|
|
{
|
|
if (eos_s3_fpga_get_status(dev) == FPGA_STATUS_ACTIVE) {
|
|
eos_s3_fpga_off(dev);
|
|
}
|
|
|
|
eos_s3_fpga_on(dev);
|
|
|
|
if (eos_s3_fpga_get_status(dev) == FPGA_STATUS_INACTIVE) {
|
|
return -EAGAIN;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int eos_s3_fpga_load(const struct device *dev, uint32_t *image_ptr, uint32_t img_size)
|
|
{
|
|
if (eos_s3_fpga_get_status(dev) == FPGA_STATUS_INACTIVE) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
volatile uint32_t *bitstream = (volatile uint32_t *)image_ptr;
|
|
|
|
for (uint32_t chunk_cnt = 0; chunk_cnt < (img_size / 4); chunk_cnt++) {
|
|
PIF->CFG_DATA = *bitstream;
|
|
bitstream++;
|
|
}
|
|
|
|
/* disable FPGA programming */
|
|
PMU->GEN_PURPOSE_0 = FB_CFG_DISABLE;
|
|
PIF->CFG_CTL = CFG_CTL_LOAD_DISABLE;
|
|
PMU->FB_ISOLATION = FB_ISOLATION_DISABLE;
|
|
|
|
/* disable software resets */
|
|
CRU->FB_SW_RESET &= ~(FB_C21_DOMAIN_SW_RESET
|
|
| FB_C16_DOMAIN_SW_RESET
|
|
| FB_C02_DOMAIN_SW_RESET
|
|
| FB_C09_DOMAIN_SW_RESET);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int eos_s3_fpga_init(const struct device *dev)
|
|
{
|
|
IO_MUX->PAD_19_CTRL = PAD_ENABLE;
|
|
|
|
struct quickfeather_fpga_data *data = dev->data;
|
|
|
|
data->FPGA_info = FPGA_INFO;
|
|
|
|
eos_s3_fpga_reset(dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct quickfeather_fpga_data fpga_data;
|
|
|
|
static const struct fpga_driver_api eos_s3_api = {
|
|
.reset = eos_s3_fpga_reset,
|
|
.load = eos_s3_fpga_load,
|
|
.get_status = eos_s3_fpga_get_status,
|
|
.on = eos_s3_fpga_on,
|
|
.off = eos_s3_fpga_off,
|
|
.get_info = eos_s3_fpga_get_info
|
|
};
|
|
|
|
DEVICE_DT_DEFINE(DT_NODELABEL(fpga0), &eos_s3_fpga_init, NULL, &fpga_data, NULL, APPLICATION,
|
|
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &eos_s3_api);
|