Line data Source code
1 : /**
2 : * @file pin_repository.cpp
3 : * @brief I/O pin registry code
4 : *
5 : * This job of this class is to make sure that we are not using same hardware pin for two
6 : * different purposes.
7 : *
8 : * @date Jan 15, 2013
9 : * @author Andrey Belomutskiy, (c) 2012-2020
10 : */
11 :
12 : #include "pch.h"
13 :
14 : PinRepository pinRepository CCM_OPTIONAL;
15 :
16 18 : static size_t getBrainPinTotalNum() {
17 18 : return BRAIN_PIN_TOTAL_PINS;
18 : }
19 :
20 19 : const char* & getBrainUsedPin(size_t index) {
21 19 : return pinRepository.getBrainUsedPin(index);
22 : }
23 :
24 : /* Common for firmware and unit tests */
25 91433 : bool isBrainPinValid(brain_pin_e brainPin) {
26 91433 : if ((brainPin == Gpio::Unassigned) || (brainPin == Gpio::Invalid))
27 89574 : return false;
28 :
29 1859 : if (brainPin > BRAIN_PIN_LAST)
30 : /* something terribly wrong */
31 0 : return false;
32 :
33 1859 : return true;
34 : }
35 :
36 1066 : int brainPin_to_index(Gpio brainPin) {
37 1066 : if (brainPin < Gpio::A0)
38 1048 : return -1;
39 :
40 18 : size_t i = brainPin - Gpio::A0;
41 :
42 18 : if (i >= getBrainPinTotalNum())
43 0 : return -1;
44 :
45 18 : return i;
46 : }
47 :
48 : /**
49 : * See also brain_pin_markUnused()
50 : * @return true if this pin was already used, false otherwise
51 : */
52 :
53 14 : bool brain_pin_markUsed(Gpio brainPin, const char *msg) {
54 : #ifndef EFI_BOOTLOADER
55 14 : efiPrintf("pin_markUsed: %s on %s", msg, hwPortname(brainPin));
56 : #endif
57 :
58 14 : int index = brainPin_to_index(brainPin);
59 14 : if (index < 0)
60 0 : return true;
61 :
62 14 : if (pinRepository.getBrainUsedPin(index) != nullptr) {
63 : // hwPortname and share a buffer behind the scenes, even while they probably never use it for different
64 : // values here let's have an explicit second buffer to make this more reliable
65 0 : char physicalPinName[32];
66 0 : strncpy(physicalPinName, hwPhysicalPinName(brainPin), sizeof(physicalPinName) - 1);
67 0 : criticalError("Pin \"%s\" (%s) required by \"%s\" but is used by \"%s\"",
68 : hwPortname(brainPin),
69 : physicalPinName,
70 : msg,
71 : getBrainUsedPin(index));
72 0 : return true;
73 : }
74 :
75 14 : getBrainUsedPin(index) = msg;
76 14 : return false;
77 : }
78 :
79 : /**
80 : * See also brain_pin_markUsed()
81 : */
82 :
83 1051 : void brain_pin_markUnused(brain_pin_e brainPin) {
84 : #ifndef EFI_BOOTLOADER
85 1051 : efiPrintf("pin_markUnused: %s", hwPortname(brainPin));
86 : #endif
87 1051 : int index = brainPin_to_index(brainPin);
88 1051 : if (index < 0)
89 1048 : return;
90 :
91 3 : getBrainUsedPin(index) = nullptr;
92 : }
93 :
94 : #if EFI_PROD_CODE
95 : #include "memstreams.h"
96 : static MemoryStream portNameStream;
97 : static char portNameBuffer[20];
98 : #endif /* EFI_PROD_CODE */
99 :
100 1 : PinRepository::PinRepository() {
101 : #if EFI_PROD_CODE
102 : msObjectInit(&portNameStream, (uint8_t*) portNameBuffer, sizeof(portNameBuffer), 0);
103 : #endif /* EFI_PROD_CODE */
104 :
105 1 : memset(PIN_USED, 0, sizeof(PIN_USED));
106 1 : }
107 :
108 : #if EFI_PROD_CODE
109 :
110 : #include "eficonsole.h"
111 : #include "drivers/gpio/gpio_ext.h"
112 : #include "smart_gpio.h"
113 : #include "hardware.h"
114 :
115 : void pinDiag2string(char *buffer, size_t size, brain_pin_diag_e pin_diag) {
116 : /* use autogeneraged helpers here? */
117 : if (pin_diag == PIN_OK) {
118 : chsnprintf(buffer, size, "Ok");
119 : } else if (pin_diag != PIN_UNKNOWN) {
120 : chsnprintf(buffer, size, "%s%s%s%s%s%s",
121 : pin_diag & PIN_DRIVER_OFF ? "driver_off " : "",
122 : pin_diag & PIN_OPEN ? "open_load " : "",
123 : pin_diag & PIN_SHORT_TO_GND ? "short_to_gnd " : "",
124 : pin_diag & PIN_SHORT_TO_BAT ? "short_to_bat " : "",
125 : pin_diag & PIN_OVERLOAD ? "overload " : "",
126 : pin_diag & PIN_DRIVER_OVERTEMP ? "overtemp": "");
127 : } else {
128 : chsnprintf(buffer, size, "INVALID");
129 : }
130 : }
131 :
132 : static brain_pin_e index_to_brainPin(unsigned int i)
133 : {
134 : if (i < getBrainPinTotalNum())
135 : return Gpio::A0 + i;
136 :
137 : return Gpio::Invalid;
138 : }
139 :
140 : static void reportPins() {
141 : int totalPinsUsed = 0;
142 :
143 : for (unsigned int i = 0; i < getBrainPinOnchipNum(); i++) {
144 : const char *pin_user = getBrainUsedPin(i);
145 :
146 : /* show used pins */
147 : if (pin_user) {
148 : static char pin_state[64];
149 : brain_pin_e brainPin = index_to_brainPin(i);
150 : int pin = getBrainPinIndex(brainPin);
151 : ioportid_t port = getBrainPinPort(brainPin);
152 : debugBrainPin(pin_state, sizeof(pin_state), brainPin);
153 :
154 : const char *boardPinName = getBoardSpecificPinName(brainPin);
155 : efiPrintf("pin %s%d (%s): %s %s", portname(port), pin, boardPinName, pin_user, pin_state);
156 : totalPinsUsed++;
157 : }
158 : }
159 :
160 : #if (BOARD_EXT_GPIOCHIPS > 0)
161 : for (unsigned int i = getBrainPinOnchipNum() ; i < getBrainPinTotalNum(); i++) {
162 : static char pin_error[64];
163 : brain_pin_e brainPin = index_to_brainPin(i);
164 :
165 : const char *pin_name = gpiochips_getPinName(brainPin);
166 : const char *pin_user = getBrainUsedPin(i);
167 : brain_pin_diag_e pin_diag = gpiochips_getDiag(brainPin);
168 :
169 : pinDiag2string(pin_error, sizeof(pin_error), pin_diag);
170 :
171 : /* here show all pins, unused too */
172 : if (pin_name) {
173 : // this probably uses a lot of output buffer!
174 : efiPrintf("ext %s: %s diagnostic: %s",
175 : pin_name, pin_user ? pin_user : "free", pin_error);
176 : } else {
177 : const char *chip_name = gpiochips_getChipName(brainPin);
178 : /* if chip exist */
179 : if (chip_name) {
180 : efiPrintf("ext %s.%d: %s diagnostic: %s",
181 : chip_name, gpiochips_getPinOffset(brainPin), pin_user ? pin_user : "free", pin_error);
182 : }
183 : }
184 : if (pin_user) {
185 : totalPinsUsed++;
186 : }
187 : }
188 : #endif
189 :
190 : efiPrintf("Total pins used: %d", totalPinsUsed);
191 :
192 : gpiochips_debug();
193 : }
194 :
195 : __attribute__((weak)) const char * getBoardSpecificPinName(brain_pin_e /*brainPin*/) {
196 : return nullptr;
197 : }
198 :
199 : const char *hwOnChipPhysicalPinName(ioportid_t hwPort, int hwPin) {
200 : portNameStream.eos = 0; // reset
201 : if (hwPort == GPIO_NULL) {
202 : return "NONE";
203 : }
204 : chprintf((BaseSequentialStream *) &portNameStream, "%s%d", portname(hwPort), hwPin);
205 : portNameStream.buffer[portNameStream.eos] = 0; // need to terminate explicitly
206 : return portNameBuffer;
207 : }
208 :
209 : const char *hwPhysicalPinName(Gpio brainPin) {
210 : if (brainPin == Gpio::Invalid) {
211 : return "INVALID";
212 : }
213 : if (brainPin == Gpio::Unassigned) {
214 : return "NONE";
215 : }
216 :
217 : if (brain_pin_is_onchip(brainPin)) {
218 : ioportid_t hwPort = getHwPort("hostname", brainPin);
219 : int hwPin = getHwPin("hostname", brainPin);
220 : return hwOnChipPhysicalPinName(hwPort, hwPin);
221 : }
222 : #if (BOARD_EXT_GPIOCHIPS > 0)
223 : else {
224 : portNameStream.eos = 0; // reset
225 : const char *pin_name = gpiochips_getPinName(brainPin);
226 :
227 : if (pin_name) {
228 : chprintf((BaseSequentialStream *) &portNameStream, "ext:%s",
229 : pin_name);
230 : } else {
231 : chprintf((BaseSequentialStream *) &portNameStream, "ext:%s.%d",
232 : gpiochips_getChipName(brainPin), gpiochips_getPinOffset(brainPin));
233 : }
234 : portNameStream.buffer[portNameStream.eos] = 0; // need to terminate explicitly
235 : return portNameBuffer;
236 : }
237 : #endif
238 : return "unexpected";
239 : }
240 :
241 : const char *hwPortname(brain_pin_e brainPin) {
242 : const char * boardSpecificPinName = getBoardSpecificPinName(brainPin);
243 : if (boardSpecificPinName != nullptr) {
244 : return boardSpecificPinName;
245 : }
246 : return hwPhysicalPinName(brainPin);
247 : }
248 :
249 : void initPinRepository(void) {
250 : /**
251 : * this method cannot use console because this method is invoked before console is initialized
252 : */
253 :
254 : addConsoleAction(CMD_PINS, reportPins);
255 :
256 : #if (BOARD_TLE8888_COUNT > 0)
257 : addConsoleAction("tle8888", tle8888_dump_regs);
258 : addConsoleAction("tle8888init", tle8888_req_init);
259 : #endif
260 : }
261 :
262 : bool brain_pin_is_onchip(brain_pin_e brainPin)
263 : {
264 : if ((brainPin < Gpio::A0) || (brainPin > BRAIN_PIN_ONCHIP_LAST))
265 : return false;
266 :
267 : return true;
268 : }
269 :
270 : bool brain_pin_is_ext(brain_pin_e brainPin)
271 : {
272 : if (brainPin > BRAIN_PIN_ONCHIP_LAST)
273 : return true;
274 :
275 : return false;
276 : }
277 :
278 : /**
279 : * Marks on-chip gpio port-pin as used. Works only for on-chip gpios
280 : * To be replaced with brain_pin_markUsed later
281 : */
282 :
283 : bool gpio_pin_markUsed(ioportid_t port, ioportmask_t pin, const char *msg) {
284 : int index = getPortPinIndex(port, pin);
285 : #ifndef EFI_BOOTLOADER
286 : efiPrintf("pin_markUsed: %s on %s", msg, hwOnChipPhysicalPinName(port, pin));
287 : #endif
288 :
289 : if (getBrainUsedPin(index) != NULL) {
290 : /**
291 : * todo: the problem is that this warning happens before the console is even
292 : * connected, so the warning is never displayed on the console and that's quite a problem!
293 : */
294 : // warning(ObdCode::OBD_PCM_Processor_Fault, "%s%d req by %s used by %s", portname(port), pin, msg, getBrainUsedPin(index));
295 : firmwareError(ObdCode::CUSTOM_ERR_PIN_ALREADY_USED_1, "%s%d req by %s used by %s", portname(port), (int)pin, msg, getBrainUsedPin(index));
296 : return true;
297 : }
298 : getBrainUsedPin(index) = msg;
299 : return false;
300 : }
301 :
302 : /**
303 : * Marks on-chip gpio port-pin as UNused. Works only for on-chip gpios
304 : * To be replaced with brain_pin_markUnused later
305 : */
306 :
307 : void gpio_pin_markUnused(ioportid_t port, ioportmask_t pin) {
308 : int index = getPortPinIndex(port, pin);
309 :
310 : getBrainUsedPin(index) = nullptr;
311 : }
312 :
313 : const char *getPinFunction(brain_input_pin_e brainPin) {
314 : int index;
315 :
316 : index = brainPin_to_index(brainPin);
317 : if (index < 0)
318 : return NULL;
319 :
320 : return getBrainUsedPin(index);
321 : }
322 : #else
323 0 : const char *hwPhysicalPinName(Gpio brainPin) {
324 0 : return "N/A";
325 : }
326 1179 : const char *hwPortname(Gpio brainPin) {
327 : (void)brainPin;
328 1179 : return "N/A";
329 : }
330 : #endif /* EFI_PROD_CODE */
|