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 <zephyr/device.h>
10 #include <zephyr/drivers/fpga.h>
11 #include "fpga_eos_s3.h"
12
eos_s3_fpga_enable_clk(void)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
eos_s3_fpga_disable_clk(void)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
eos_s3_fpga_get_status(const struct device * dev)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
eos_s3_fpga_get_info(const struct device * dev)44 static const char *eos_s3_fpga_get_info(const struct device *dev)
45 {
46 struct quickfeather_fpga_data *data = dev->data;
47
48 return data->FPGA_info;
49 }
50
eos_s3_fpga_on(const struct device * dev)51 static int eos_s3_fpga_on(const struct device *dev)
52 {
53 if (eos_s3_fpga_get_status(dev) == FPGA_STATUS_ACTIVE) {
54 return 0;
55 }
56
57 /* wake up the FPGA power domain */
58 PMU->FFE_FB_PF_SW_WU = PMU_FFE_FB_PF_SW_WU_FB_WU;
59 while (PMU->FFE_FB_PF_SW_WU == PMU_FFE_FB_PF_SW_WU_FB_WU) {
60 /* The register will clear itself if the FPGA starts */
61 };
62
63 eos_s3_fpga_enable_clk();
64
65 /* enable FPGA programming */
66 PMU->GEN_PURPOSE_0 = FB_CFG_ENABLE;
67 PIF->CFG_CTL = CFG_CTL_LOAD_ENABLE;
68
69 return 0;
70 }
71
eos_s3_fpga_off(const struct device * dev)72 static int eos_s3_fpga_off(const struct device *dev)
73 {
74 if (eos_s3_fpga_get_status(dev) == FPGA_STATUS_INACTIVE) {
75 return 0;
76 }
77
78 PMU->FB_PWR_MODE_CFG = PMU_FB_PWR_MODE_CFG_FB_SD;
79 PMU->FFE_FB_PF_SW_PD = PMU_FFE_FB_PF_SW_PD_FB_PD;
80
81 eos_s3_fpga_disable_clk();
82
83 return 0;
84 }
85
eos_s3_fpga_reset(const struct device * dev)86 static int eos_s3_fpga_reset(const struct device *dev)
87 {
88 if (eos_s3_fpga_get_status(dev) == FPGA_STATUS_ACTIVE) {
89 eos_s3_fpga_off(dev);
90 }
91
92 eos_s3_fpga_on(dev);
93
94 if (eos_s3_fpga_get_status(dev) == FPGA_STATUS_INACTIVE) {
95 return -EAGAIN;
96 }
97
98 return 0;
99 }
100
eos_s3_fpga_load(const struct device * dev,uint32_t * image_ptr,uint32_t img_size)101 static int eos_s3_fpga_load(const struct device *dev, uint32_t *image_ptr, uint32_t img_size)
102 {
103 if (eos_s3_fpga_get_status(dev) == FPGA_STATUS_INACTIVE) {
104 return -EINVAL;
105 }
106
107 volatile uint32_t *bitstream = (volatile uint32_t *)image_ptr;
108
109 for (uint32_t chunk_cnt = 0; chunk_cnt < (img_size / 4); chunk_cnt++) {
110 PIF->CFG_DATA = *bitstream;
111 bitstream++;
112 }
113
114 /* disable FPGA programming */
115 PMU->GEN_PURPOSE_0 = FB_CFG_DISABLE;
116 PIF->CFG_CTL = CFG_CTL_LOAD_DISABLE;
117 PMU->FB_ISOLATION = FB_ISOLATION_DISABLE;
118
119 /* disable software resets */
120 CRU->FB_SW_RESET &= ~(FB_C21_DOMAIN_SW_RESET
121 | FB_C16_DOMAIN_SW_RESET
122 | FB_C02_DOMAIN_SW_RESET
123 | FB_C09_DOMAIN_SW_RESET);
124
125 return 0;
126 }
127
eos_s3_fpga_init(const struct device * dev)128 static int eos_s3_fpga_init(const struct device *dev)
129 {
130 IO_MUX->PAD_19_CTRL = PAD_ENABLE;
131
132 struct quickfeather_fpga_data *data = dev->data;
133
134 data->FPGA_info = FPGA_INFO;
135
136 eos_s3_fpga_reset(dev);
137
138 return 0;
139 }
140
141 static struct quickfeather_fpga_data fpga_data;
142
143 static DEVICE_API(fpga, eos_s3_api) = {
144 .reset = eos_s3_fpga_reset,
145 .load = eos_s3_fpga_load,
146 .get_status = eos_s3_fpga_get_status,
147 .on = eos_s3_fpga_on,
148 .off = eos_s3_fpga_off,
149 .get_info = eos_s3_fpga_get_info
150 };
151
152 DEVICE_DT_DEFINE(DT_NODELABEL(fpga0), &eos_s3_fpga_init, NULL, &fpga_data, NULL, POST_KERNEL,
153 CONFIG_FPGA_INIT_PRIORITY, &eos_s3_api);
154