|
| 1 | +/* |
| 2 | + * Copyright (c) 2021 Antmicro <www.antmicro.com> |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: Apache-2.0 |
| 5 | + */ |
| 6 | + |
| 7 | +#include <errno.h> |
| 8 | +#include <string.h> |
| 9 | +#include <device.h> |
| 10 | +#include <drivers/fpga.h> |
| 11 | +#include "fpga_eos_s3.h" |
| 12 | + |
| 13 | +void eos_s3_fpga_enable_clk(void) |
| 14 | +{ |
| 15 | + CRU->C16_CLK_GATE = C16_CLK_GATE_PATH_0_ON; |
| 16 | + CRU->C21_CLK_GATE = C21_CLK_GATE_PATH_0_ON; |
| 17 | + CRU->C09_CLK_GATE = C09_CLK_GATE_PATH_1_ON | C09_CLK_GATE_PATH_2_ON; |
| 18 | + CRU->C02_CLK_GATE = C02_CLK_GATE_PATH_1_ON; |
| 19 | +} |
| 20 | + |
| 21 | +void eos_s3_fpga_disable_clk(void) |
| 22 | +{ |
| 23 | + CRU->C16_CLK_GATE = C16_CLK_GATE_PATH_0_OFF; |
| 24 | + CRU->C21_CLK_GATE = C21_CLK_GATE_PATH_0_OFF; |
| 25 | + CRU->C09_CLK_GATE = C09_CLK_GATE_PATH_1_OFF | C09_CLK_GATE_PATH_2_OFF; |
| 26 | + CRU->C02_CLK_GATE = C02_CLK_GATE_PATH_1_OFF; |
| 27 | +} |
| 28 | + |
| 29 | +struct quickfeather_fpga_data { |
| 30 | + char *FPGA_info; |
| 31 | +}; |
| 32 | + |
| 33 | +static enum FPGA_status eos_s3_fpga_get_status(const struct device *dev) |
| 34 | +{ |
| 35 | + ARG_UNUSED(dev); |
| 36 | + |
| 37 | + if (PMU->FB_STATUS == FPGA_STATUS_ACTIVE) { |
| 38 | + return FPGA_STATUS_ACTIVE; |
| 39 | + } else |
| 40 | + return FPGA_STATUS_INACTIVE; |
| 41 | +} |
| 42 | + |
| 43 | +static const char *eos_s3_fpga_get_info(const struct device *dev) |
| 44 | +{ |
| 45 | + struct quickfeather_fpga_data *data = dev->data; |
| 46 | + |
| 47 | + return data->FPGA_info; |
| 48 | +} |
| 49 | + |
| 50 | +static int eos_s3_fpga_on(const struct device *dev) |
| 51 | +{ |
| 52 | + if (eos_s3_fpga_get_status(dev) == FPGA_STATUS_ACTIVE) { |
| 53 | + return 0; |
| 54 | + } |
| 55 | + |
| 56 | + /* wake up the FPGA power domain */ |
| 57 | + PMU->FFE_FB_PF_SW_WU = PMU_FFE_FB_PF_SW_WU_FB_WU; |
| 58 | + while (PMU->FFE_FB_PF_SW_WU == PMU_FFE_FB_PF_SW_WU_FB_WU) { |
| 59 | + /* The register will clear itself if the FPGA starts */ |
| 60 | + }; |
| 61 | + |
| 62 | + eos_s3_fpga_enable_clk(); |
| 63 | + |
| 64 | + /* enable FPGA programming */ |
| 65 | + PMU->GEN_PURPOSE_0 = FB_CFG_ENABLE; |
| 66 | + PIF->CFG_CTL = CFG_CTL_LOAD_ENABLE; |
| 67 | + |
| 68 | + return 0; |
| 69 | +} |
| 70 | + |
| 71 | +static int eos_s3_fpga_off(const struct device *dev) |
| 72 | +{ |
| 73 | + if (eos_s3_fpga_get_status(dev) == FPGA_STATUS_INACTIVE) { |
| 74 | + return 0; |
| 75 | + } |
| 76 | + |
| 77 | + PMU->FB_PWR_MODE_CFG = PMU_FB_PWR_MODE_CFG_FB_SD; |
| 78 | + PMU->FFE_FB_PF_SW_PD = PMU_FFE_FB_PF_SW_PD_FB_PD; |
| 79 | + |
| 80 | + eos_s3_fpga_disable_clk(); |
| 81 | + |
| 82 | + return 0; |
| 83 | +} |
| 84 | + |
| 85 | +static int eos_s3_fpga_reset(const struct device *dev) |
| 86 | +{ |
| 87 | + if (eos_s3_fpga_get_status(dev) == FPGA_STATUS_ACTIVE) { |
| 88 | + eos_s3_fpga_off(dev); |
| 89 | + } |
| 90 | + |
| 91 | + eos_s3_fpga_on(dev); |
| 92 | + |
| 93 | + if (eos_s3_fpga_get_status(dev) == FPGA_STATUS_INACTIVE) { |
| 94 | + return -EAGAIN; |
| 95 | + } |
| 96 | + |
| 97 | + return 0; |
| 98 | +} |
| 99 | + |
| 100 | +static int eos_s3_fpga_load(const struct device *dev, uint32_t *image_ptr, uint32_t img_size) |
| 101 | +{ |
| 102 | + if (eos_s3_fpga_get_status(dev) == FPGA_STATUS_INACTIVE) { |
| 103 | + return -EINVAL; |
| 104 | + } |
| 105 | + |
| 106 | + volatile uint32_t *bitstream = (volatile uint32_t *)image_ptr; |
| 107 | + |
| 108 | + for (uint32_t chunk_cnt = 0; chunk_cnt < (img_size / 4); chunk_cnt++) { |
| 109 | + PIF->CFG_DATA = *bitstream; |
| 110 | + bitstream++; |
| 111 | + } |
| 112 | + |
| 113 | + /* disable FPGA programming */ |
| 114 | + PMU->GEN_PURPOSE_0 = FB_CFG_DISABLE; |
| 115 | + PIF->CFG_CTL = CFG_CTL_LOAD_DISABLE; |
| 116 | + PMU->FB_ISOLATION = FB_ISOLATION_DISABLE; |
| 117 | + |
| 118 | + return 0; |
| 119 | +} |
| 120 | + |
| 121 | +static int eos_s3_fpga_init(const struct device *dev) |
| 122 | +{ |
| 123 | + IO_MUX->PAD_19_CTRL = PAD_ENABLE; |
| 124 | + |
| 125 | + struct quickfeather_fpga_data *data = dev->data; |
| 126 | + |
| 127 | + data->FPGA_info = FPGA_INFO; |
| 128 | + |
| 129 | + eos_s3_fpga_reset(dev); |
| 130 | + |
| 131 | + return 0; |
| 132 | +} |
| 133 | + |
| 134 | +static struct quickfeather_fpga_data fpga_data; |
| 135 | + |
| 136 | +static const struct fpga_driver_api eos_s3_api = { |
| 137 | + .reset = eos_s3_fpga_reset, |
| 138 | + .load = eos_s3_fpga_load, |
| 139 | + .get_status = eos_s3_fpga_get_status, |
| 140 | + .on = eos_s3_fpga_on, |
| 141 | + .off = eos_s3_fpga_off, |
| 142 | + .get_info = eos_s3_fpga_get_info |
| 143 | +}; |
| 144 | + |
| 145 | +DEVICE_DEFINE(fpga, "FPGA", &eos_s3_fpga_init, NULL, &fpga_data, NULL, APPLICATION, |
| 146 | + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &eos_s3_api); |
0 commit comments