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