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