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
eos_s3_fpga_get_info(const struct device * dev)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
eos_s3_fpga_on(const struct device * dev)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
eos_s3_fpga_off(const struct device * dev)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
eos_s3_fpga_reset(const struct device * dev)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
eos_s3_fpga_load(const struct device * dev,uint32_t * image_ptr,uint32_t img_size)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 /* disable software resets */
119 CRU->FB_SW_RESET &= ~(FB_C21_DOMAIN_SW_RESET
120 | FB_C16_DOMAIN_SW_RESET
121 | FB_C02_DOMAIN_SW_RESET
122 | FB_C09_DOMAIN_SW_RESET);
123
124 return 0;
125 }
126
eos_s3_fpga_init(const struct device * dev)127 static int eos_s3_fpga_init(const struct device *dev)
128 {
129 IO_MUX->PAD_19_CTRL = PAD_ENABLE;
130
131 struct quickfeather_fpga_data *data = dev->data;
132
133 data->FPGA_info = FPGA_INFO;
134
135 eos_s3_fpga_reset(dev);
136
137 return 0;
138 }
139
140 static struct quickfeather_fpga_data fpga_data;
141
142 static const struct fpga_driver_api eos_s3_api = {
143 .reset = eos_s3_fpga_reset,
144 .load = eos_s3_fpga_load,
145 .get_status = eos_s3_fpga_get_status,
146 .on = eos_s3_fpga_on,
147 .off = eos_s3_fpga_off,
148 .get_info = eos_s3_fpga_get_info
149 };
150
151 DEVICE_DT_DEFINE(DT_NODELABEL(fpga0), &eos_s3_fpga_init, NULL, &fpga_data, NULL, POST_KERNEL,
152 CONFIG_FPGA_INIT_PRIORITY, &eos_s3_api);
153