1 /*
2  * Copyright (c) 2023 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT intel_timeaware_gpio
8 
9 #include <errno.h>
10 #include <stdio.h>
11 #include <zephyr/device.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/drivers/misc/timeaware_gpio/timeaware_gpio.h>
14 #include <zephyr/devicetree.h>
15 #include <zephyr/internal/syscall_handler.h>
16 
17 /* TGPIO Register offsets */
18 #define ART_L           0x00 /* ART lower 32 bit reg */
19 #define ART_H           0x04 /* ART higher 32 bit reg */
20 #define CTL             0x10 /* TGPIO control reg */
21 #define COMPV31_0       0x20 /* Comparator lower 32 bit reg */
22 #define COMPV63_32      0x24 /* Comparator higher 32 bit reg */
23 #define PIV31_0         0x28 /* Periodic Interval lower 32 bit reg */
24 #define PIV63_32        0x2c /* Periodic Interval higher 32 bit reg */
25 #define TCV31_0         0x30 /* Time Capture lower 32 bit reg */
26 #define TCV63_32        0x34 /* Time Capture higher 32 bit reg */
27 #define ECCV31_0        0x38 /* Event Counter Capture lower 32 bit reg */
28 #define ECCV63_32       0x3c /* Event Counter Capture higher 32 bit reg */
29 #define EC31_0          0x40 /* Event Counter lower 32 bit reg */
30 #define EC63_32         0x44 /* Event Counter higher 32 bit reg */
31 #define REGSET_SIZE     0x100 /* Difference between 0 and 1 */
32 #define UINT32_MASK     0xFFFFFFFF /* 32 bit Mask */
33 #define UINT32_SIZE     32
34 
35 /* Control Register */
36 #define CTL_EN                  BIT(0) /* Control enable */
37 #define CTL_DIR                 BIT(1) /* Control disable */
38 #define CTL_EP                  GENMASK(3, 2) /* Recerved polarity */
39 #define CTL_EP_RISING_EDGE      (0 << 2) /* Rising edge */
40 #define CTL_EP_FALLING_EDGE     (1 << 2) /* Falling edge */
41 #define CTL_EP_TOGGLE_EDGE      (2 << 2) /* Toggle edge */
42 #define CTL_PM                  BIT(4) /* Periodic mode */
43 
44 /* Macro to get configuration data, required by DEVICE_MMIO_NAMED_* in init */
45 #define DEV_CFG(_dev) \
46 	((const struct tgpio_config *)(_dev)->config)
47 /* Macro to get runtime data, required by DEVICE_MMIO_NAMED_* in init */
48 #define DEV_DATA(_dev) ((struct tgpio_runtime *)(_dev)->data)
49 /* Macro to individual pin regbase */
50 #define pin_regs(addr, pin) (addr + (pin * REGSET_SIZE))
51 
52 struct tgpio_config {
53 	DEVICE_MMIO_NAMED_ROM(reg_base);
54 	uint32_t max_pins;
55 	uint32_t art_clock_freq;
56 };
57 
58 struct tgpio_runtime {
59 	DEVICE_MMIO_NAMED_RAM(reg_base);
60 };
61 
regs(const struct device * dev)62 static mm_reg_t regs(const struct device *dev)
63 {
64 	return DEVICE_MMIO_NAMED_GET(dev, reg_base);
65 }
66 
tgpio_intel_get_time(const struct device * dev,uint64_t * current_time)67 static int tgpio_intel_get_time(const struct device *dev,
68 					uint64_t *current_time)
69 {
70 	*current_time = sys_read32(regs(dev) + ART_L);
71 	*current_time += ((uint64_t)sys_read32(regs(dev) + ART_H) << UINT32_SIZE);
72 
73 	return 0;
74 }
75 
tgpio_intel_cyc_per_sec(const struct device * dev,uint32_t * cycles)76 static int tgpio_intel_cyc_per_sec(const struct device *dev,
77 					   uint32_t *cycles)
78 {
79 	*cycles = DEV_CFG(dev)->art_clock_freq;
80 
81 	return 0;
82 }
83 
tgpio_intel_pin_disable(const struct device * dev,uint32_t pin)84 static int tgpio_intel_pin_disable(const struct device *dev,
85 					   uint32_t pin)
86 {
87 	mm_reg_t addr = regs(dev);
88 
89 	if (pin >= DEV_CFG(dev)->max_pins) {
90 		return -EINVAL;
91 	}
92 
93 	addr = pin_regs(addr, pin);
94 	sys_write32(sys_read32(addr + CTL) & ~CTL_EN, addr + CTL);
95 
96 	return 0;
97 }
98 
tgpio_intel_periodic_output(const struct device * dev,uint32_t pin,uint64_t start_time,uint64_t repeat_interval,bool periodic_enable)99 static int tgpio_intel_periodic_output(const struct device *dev,
100 					       uint32_t pin,
101 					       uint64_t start_time,
102 					       uint64_t repeat_interval,
103 					       bool periodic_enable)
104 {
105 	mm_reg_t addr = regs(dev);
106 	uint32_t val;
107 
108 	if (pin >= DEV_CFG(dev)->max_pins) {
109 		return -EINVAL;
110 	}
111 
112 	addr = pin_regs(addr, pin);
113 	tgpio_intel_pin_disable(dev, pin);
114 
115 	/* Configure PIV */
116 	val = (repeat_interval >> UINT32_SIZE) & UINT32_MASK;
117 	sys_write32(val, addr + PIV63_32);
118 	val = repeat_interval & UINT32_MASK;
119 	sys_write32(val, addr + PIV31_0);
120 
121 	/* Configure COMPV */
122 	val = (start_time >> UINT32_SIZE) & UINT32_MASK;
123 	sys_write32(val, addr + COMPV63_32);
124 	val = start_time & UINT32_MASK;
125 	sys_write32(val, addr + COMPV31_0);
126 
127 	val = 0;
128 
129 	/* Configure Periodic Mode */
130 	if (periodic_enable) {
131 		val |= CTL_PM;
132 	}
133 
134 	/* Enable the pin */
135 	val |= CTL_EN;
136 	sys_write32(val, addr + CTL);
137 
138 	return 0;
139 }
140 
tgpio_intel_config_external_timestamp(const struct device * dev,uint32_t pin,uint32_t event_polarity)141 static int tgpio_intel_config_external_timestamp(const struct device *dev,
142 							 uint32_t pin,
143 							 uint32_t event_polarity)
144 {
145 	mm_reg_t addr = regs(dev);
146 	uint32_t val;
147 
148 	if (pin >= DEV_CFG(dev)->max_pins) {
149 		return -EINVAL;
150 	}
151 
152 	addr = pin_regs(addr, pin);
153 	tgpio_intel_pin_disable(dev, pin);
154 
155 	/* Configure interrupt polarity */
156 	if (event_polarity == 0) {
157 		val = CTL_EP_RISING_EDGE;
158 	} else if (event_polarity == 1) {
159 		val = CTL_EP_FALLING_EDGE;
160 	} else {
161 		val = CTL_EP_TOGGLE_EDGE;
162 	}
163 
164 	/* Configure direction = input */
165 	val |= CTL_DIR;
166 	sys_write32(val, addr + CTL);
167 
168 	/* Enable the pin */
169 	sys_write32(sys_read32(addr + CTL) | CTL_EN, addr + CTL);
170 
171 	return 0;
172 }
173 
tgpio_intel_read_ts_ec(const struct device * dev,uint32_t pin,uint64_t * timestamp,uint64_t * event_count)174 static int tgpio_intel_read_ts_ec(const struct device *dev,
175 					  uint32_t pin,
176 					  uint64_t *timestamp,
177 					  uint64_t *event_count)
178 {
179 	if (pin >= DEV_CFG(dev)->max_pins) {
180 		return -EINVAL;
181 	}
182 
183 	*timestamp = sys_read32(regs(dev) + TCV31_0);
184 	*timestamp += ((uint64_t)sys_read32(regs(dev) + TCV63_32) << UINT32_SIZE);
185 	*event_count = sys_read32(regs(dev) + ECCV31_0);
186 	*event_count += ((uint64_t)sys_read32(regs(dev) + ECCV63_32) << UINT32_SIZE);
187 
188 	return 0;
189 }
190 
191 static DEVICE_API(tgpio, api_funcs) = {
192 	.pin_disable = tgpio_intel_pin_disable,
193 	.get_time = tgpio_intel_get_time,
194 	.set_perout = tgpio_intel_periodic_output,
195 	.config_ext_ts = tgpio_intel_config_external_timestamp,
196 	.read_ts_ec = tgpio_intel_read_ts_ec,
197 	.cyc_per_sec = tgpio_intel_cyc_per_sec,
198 };
199 
tgpio_init(const struct device * dev)200 static int tgpio_init(const struct device *dev)
201 {
202 	const struct tgpio_config *cfg = DEV_CFG(dev);
203 	struct tgpio_runtime *rt = DEV_DATA(dev);
204 
205 	device_map(&rt->reg_base,
206 		   cfg->reg_base.phys_addr & ~0xFFU,
207 		   cfg->reg_base.size,
208 		   K_MEM_CACHE_NONE);
209 
210 	return 0;
211 }
212 
213 #define TGPIO_INTEL_DEV_CFG_DATA(n)					       \
214 	static const struct tgpio_config				       \
215 		tgpio_##n##_cfg = {					       \
216 		DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_DRV_INST(n)),	       \
217 		.max_pins = DT_INST_PROP(n, max_pins),			       \
218 		.art_clock_freq = DT_INST_PROP(n, timer_clock),		       \
219 	};								       \
220 									       \
221 	static struct tgpio_runtime tgpio_##n##_runtime;		       \
222 									       \
223 	DEVICE_DT_INST_DEFINE(n,					       \
224 			      &tgpio_init,				       \
225 			      NULL,					       \
226 			      &tgpio_##n##_runtime,			       \
227 			      &tgpio_##n##_cfg,			       \
228 			      POST_KERNEL, CONFIG_TIMEAWARE_GPIO_INIT_PRIORITY,\
229 			      &api_funcs);				       \
230 
231 DT_INST_FOREACH_STATUS_OKAY(TGPIO_INTEL_DEV_CFG_DATA)
232