1 /*
2  * SPDX-License-Identifier: Apache-2.0
3  * Copyright (c) 2024 sensry.io
4  */
5 
6 #include "soc.h"
7 #include "udma.h"
8 
9 #define SY1XX_UDMA_CTRL_PER_CG (SY1XX_ARCHI_UDMA_ADDR + SY1XX_UDMA_CONF_OFFSET)
10 
11 #define SY1XX_MAX_UART_COUNT 3
12 #define SY1XX_MAX_I2C_COUNT  4
13 #define SY1XX_MAX_SPI_COUNT  7
14 #define SY1XX_MAX_ETH_COUNT  1
15 
sy1xx_udma_enable_clock(sy1xx_udma_module_t module,uint32_t instance)16 void sy1xx_udma_enable_clock(sy1xx_udma_module_t module, uint32_t instance)
17 {
18 
19 	uint32_t udma_ctrl_per_cg = sys_read32(SY1XX_UDMA_CTRL_PER_CG);
20 
21 	switch (module) {
22 
23 	case SY1XX_UDMA_MODULE_UART:
24 		if (instance >= SY1XX_MAX_UART_COUNT) {
25 			return;
26 		}
27 		udma_ctrl_per_cg |= 1 << (instance + 0);
28 		break;
29 
30 	case SY1XX_UDMA_MODULE_I2C:
31 		if (instance >= SY1XX_MAX_I2C_COUNT) {
32 			return;
33 		}
34 		udma_ctrl_per_cg |= 1 << (instance + 10);
35 		break;
36 
37 	case SY1XX_UDMA_MODULE_SPI:
38 		if (instance >= SY1XX_MAX_SPI_COUNT) {
39 			return;
40 		}
41 		udma_ctrl_per_cg |= 1 << (instance + 3);
42 		break;
43 
44 	case SY1XX_UDMA_MODULE_MAC:
45 		if (instance >= SY1XX_MAX_ETH_COUNT) {
46 			return;
47 		}
48 		udma_ctrl_per_cg |= 1 << (instance + 20);
49 		break;
50 
51 	case SY1XX_UDMA_MAX_MODULE_COUNT:
52 		break;
53 	}
54 
55 	sys_write32(udma_ctrl_per_cg, SY1XX_UDMA_CTRL_PER_CG);
56 }
57 
sy1xx_udma_disable_clock(sy1xx_udma_module_t module,uint32_t instance)58 void sy1xx_udma_disable_clock(sy1xx_udma_module_t module, uint32_t instance)
59 {
60 
61 	uint32_t udma_ctrl_per_cg = sys_read32(SY1XX_UDMA_CTRL_PER_CG);
62 
63 	switch (module) {
64 
65 	case SY1XX_UDMA_MODULE_UART:
66 		if (instance >= SY1XX_MAX_UART_COUNT) {
67 			return;
68 		}
69 		udma_ctrl_per_cg &= ~(1 << (instance + 0));
70 		break;
71 
72 	case SY1XX_UDMA_MODULE_I2C:
73 		if (instance >= SY1XX_MAX_I2C_COUNT) {
74 			return;
75 		}
76 		udma_ctrl_per_cg &= ~(1 << (instance + 10));
77 		break;
78 
79 	case SY1XX_UDMA_MODULE_SPI:
80 		if (instance >= SY1XX_MAX_SPI_COUNT) {
81 			return;
82 		}
83 		udma_ctrl_per_cg &= ~(1 << (instance + 3));
84 		break;
85 
86 	case SY1XX_UDMA_MODULE_MAC:
87 		if (instance >= SY1XX_MAX_ETH_COUNT) {
88 			return;
89 		}
90 		udma_ctrl_per_cg &= ~(1 << (instance + 20));
91 		break;
92 
93 	case SY1XX_UDMA_MAX_MODULE_COUNT:
94 		break;
95 	}
96 
97 	sys_write32(udma_ctrl_per_cg, SY1XX_UDMA_CTRL_PER_CG);
98 }
99 
sy1xx_udma_busy_delay(uint32_t msec)100 void sy1xx_udma_busy_delay(uint32_t msec)
101 {
102 	uint32_t sec = 250000000;
103 	uint32_t millis = (sec / 1000) * msec;
104 
105 	for (uint32_t i = 0; i < millis; i++) {
106 		__asm__("nop");
107 	}
108 }
109 
sy1xx_udma_cancel(uint32_t base,uint32_t channel)110 int32_t sy1xx_udma_cancel(uint32_t base, uint32_t channel)
111 {
112 	uint32_t channel_offset = channel == 0 ? 0x00 : 0x10;
113 
114 	/* clear existing */
115 	SY1XX_UDMA_WRITE_REG(base, SY1XX_UDMA_CFG_REG + channel_offset,
116 			     SY1XX_UDMA_CHANNEL_CFG_CLEAR);
117 	return 0;
118 }
119 
sy1xx_udma_is_ready(uint32_t base,uint32_t channel)120 int32_t sy1xx_udma_is_ready(uint32_t base, uint32_t channel)
121 {
122 	uint32_t channel_offset = channel == 0 ? 0x00 : 0x10;
123 
124 	int32_t isBusy = SY1XX_UDMA_READ_REG(base, SY1XX_UDMA_CFG_REG + channel_offset) &
125 			 (SY1XX_UDMA_CHANNEL_CFG_EN);
126 
127 	return isBusy ? 0 : 1;
128 }
129 
sy1xx_udma_wait_for_finished(uint32_t base,uint32_t channel)130 int32_t sy1xx_udma_wait_for_finished(uint32_t base, uint32_t channel)
131 {
132 	uint32_t channel_offset = channel == 0 ? 0x00 : 0x10;
133 
134 	volatile uint32_t timeout = 200;
135 
136 	while (SY1XX_UDMA_READ_REG(base, SY1XX_UDMA_CFG_REG + channel_offset) &
137 	       (SY1XX_UDMA_CHANNEL_CFG_EN)) {
138 		sy1xx_udma_busy_delay(1);
139 		timeout--;
140 		if (timeout == 0) {
141 			return -1;
142 		}
143 	}
144 
145 	return 0;
146 }
147 
sy1xx_udma_wait_for_status(uint32_t base)148 int32_t sy1xx_udma_wait_for_status(uint32_t base)
149 {
150 
151 	volatile uint32_t timeout = 200;
152 
153 	while (SY1XX_UDMA_READ_REG(base, SY1XX_UDMA_STATUS) & (0x3)) {
154 		sy1xx_udma_busy_delay(1);
155 		timeout--;
156 		if (timeout == 0) {
157 			return -1;
158 		}
159 	}
160 
161 	return 0;
162 }
163 
sy1xx_udma_start(uint32_t base,uint32_t channel,uint32_t saddr,uint32_t size,uint32_t optional_cfg)164 int32_t sy1xx_udma_start(uint32_t base, uint32_t channel, uint32_t saddr, uint32_t size,
165 			 uint32_t optional_cfg)
166 {
167 	uint32_t channel_offset = channel == 0 ? 0x00 : 0x10;
168 
169 	SY1XX_UDMA_WRITE_REG(base, SY1XX_UDMA_SADDR_REG + channel_offset, saddr);
170 	SY1XX_UDMA_WRITE_REG(base, SY1XX_UDMA_SIZE_REG + channel_offset, size);
171 	SY1XX_UDMA_WRITE_REG(base, SY1XX_UDMA_CFG_REG + channel_offset,
172 			     SY1XX_UDMA_CHANNEL_CFG_EN | optional_cfg);
173 
174 	return 0;
175 }
176 
sy1xx_udma_get_remaining(uint32_t base,uint32_t channel)177 int32_t sy1xx_udma_get_remaining(uint32_t base, uint32_t channel)
178 {
179 	uint32_t channel_offset = channel == 0 ? 0x00 : 0x10;
180 
181 	int32_t size = SY1XX_UDMA_READ_REG(base, SY1XX_UDMA_SIZE_REG + channel_offset);
182 
183 	return size;
184 }
185