1*8d2c75e4Smpi /* $OpenBSD: tcpcib.c,v 1.9 2022/03/11 18:00:52 mpi Exp $ */
2f6ad04e6Sjsg
3f6ad04e6Sjsg /*
4f6ad04e6Sjsg * Copyright (c) 2012 Matt Dainty <matt@bodgit-n-scarper.com>
5f6ad04e6Sjsg *
6f6ad04e6Sjsg * Permission to use, copy, modify, and distribute this software for any
7f6ad04e6Sjsg * purpose with or without fee is hereby granted, provided that the above
8f6ad04e6Sjsg * copyright notice and this permission notice appear in all copies.
9f6ad04e6Sjsg *
10f6ad04e6Sjsg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11f6ad04e6Sjsg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12f6ad04e6Sjsg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13f6ad04e6Sjsg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14f6ad04e6Sjsg * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
15f6ad04e6Sjsg * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16f6ad04e6Sjsg * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17f6ad04e6Sjsg */
18f6ad04e6Sjsg
19f6ad04e6Sjsg /*
2018078679Skettenis * Intel Atom E600 series LPC bridge also containing HPET and watchdog
21f6ad04e6Sjsg */
22f6ad04e6Sjsg
23f6ad04e6Sjsg #include <sys/param.h>
24f6ad04e6Sjsg #include <sys/systm.h>
25f6ad04e6Sjsg #include <sys/device.h>
2618078679Skettenis #include <sys/timetc.h>
27f6ad04e6Sjsg
28f6ad04e6Sjsg #include <machine/bus.h>
29f6ad04e6Sjsg
30f6ad04e6Sjsg #include <dev/pci/pcireg.h>
31f6ad04e6Sjsg #include <dev/pci/pcivar.h>
32f6ad04e6Sjsg #include <dev/pci/pcidevs.h>
33f6ad04e6Sjsg
34f6ad04e6Sjsg #define E600_LPC_SMBA 0x40 /* SMBus Base Address */
35f6ad04e6Sjsg #define E600_LPC_GBA 0x44 /* GPIO Base Address */
36f6ad04e6Sjsg #define E600_LPC_WDTBA 0x84 /* WDT Base Address */
37f6ad04e6Sjsg
38f6ad04e6Sjsg #define E600_WDT_SIZE 64 /* I/O region size */
39f6ad04e6Sjsg #define E600_WDT_PV1 0x00 /* Preload Value 1 Register */
40f6ad04e6Sjsg #define E600_WDT_PV2 0x04 /* Preload Value 2 Register */
41f6ad04e6Sjsg #define E600_WDT_RR0 0x0c /* Reload Register 0 */
42f6ad04e6Sjsg #define E600_WDT_RR1 0x0d /* Reload Register 1 */
43f6ad04e6Sjsg #define E600_WDT_RR1_RELOAD (1 << 0) /* WDT Reload Flag */
44f6ad04e6Sjsg #define E600_WDT_RR1_TIMEOUT (1 << 1) /* WDT Timeout Flag */
45f6ad04e6Sjsg #define E600_WDT_WDTCR 0x10 /* WDT Configuration Register */
46f6ad04e6Sjsg #define E600_WDT_WDTCR_PRE (1 << 2) /* WDT Prescalar Select */
47f6ad04e6Sjsg #define E600_WDT_WDTCR_RESET (1 << 3) /* WDT Reset Select */
48f6ad04e6Sjsg #define E600_WDT_WDTCR_ENABLE (1 << 4) /* WDT Reset Enable */
49f6ad04e6Sjsg #define E600_WDT_WDTCR_TIMEOUT (1 << 5) /* WDT Timeout Output Enable */
50f6ad04e6Sjsg #define E600_WDT_DCR 0x14 /* Down Counter Register */
51f6ad04e6Sjsg #define E600_WDT_WDTLR 0x18 /* WDT Lock Register */
52f6ad04e6Sjsg #define E600_WDT_WDTLR_LOCK (1 << 0) /* Watchdog Timer Lock */
53f6ad04e6Sjsg #define E600_WDT_WDTLR_ENABLE (1 << 1) /* Watchdog Timer Enable */
54f6ad04e6Sjsg #define E600_WDT_WDTLR_TIMEOUT (1 << 2) /* WDT Timeout Configuration */
55f6ad04e6Sjsg
5618078679Skettenis #define E600_HPET_BASE 0xfed00000 /* HPET register base */
5718078679Skettenis #define E600_HPET_SIZE 0x00000400 /* HPET register size */
5818078679Skettenis
5918078679Skettenis #define E600_HPET_GCID 0x000 /* Capabilities and ID */
6018078679Skettenis #define E600_HPET_GCID_WIDTH (1 << 13) /* Counter Size */
6118078679Skettenis #define E600_HPET_PERIOD 0x004 /* Counter Tick Period */
6218078679Skettenis #define E600_HPET_GC 0x010 /* General Configuration */
6318078679Skettenis #define E600_HPET_GC_ENABLE (1 << 0) /* Overall Enable */
6418078679Skettenis #define E600_HPET_GIS 0x020 /* General Interrupt Status */
6518078679Skettenis #define E600_HPET_MCV 0x0f0 /* Main Counter Value */
6618078679Skettenis #define E600_HPET_T0C 0x100 /* Timer 0 Config and Capabilities */
6718078679Skettenis #define E600_HPET_T0CV 0x108 /* Timer 0 Comparator Value */
6818078679Skettenis #define E600_HPET_T1C 0x120 /* Timer 1 Config and Capabilities */
6918078679Skettenis #define E600_HPET_T1CV 0x128 /* Timer 1 Comparator Value */
7018078679Skettenis #define E600_HPET_T2C 0x140 /* Timer 2 Config and Capabilities */
7118078679Skettenis #define E600_HPET_T2CV 0x148 /* Timer 2 Comparator Value */
7218078679Skettenis
73f6ad04e6Sjsg struct tcpcib_softc {
74f6ad04e6Sjsg struct device sc_dev;
75f6ad04e6Sjsg
76f6ad04e6Sjsg /* Keep track of which parts of the hardware are active */
77f6ad04e6Sjsg int sc_active;
78f6ad04e6Sjsg #define E600_WDT_ACTIVE (1 << 0)
7918078679Skettenis #define E600_HPET_ACTIVE (1 << 1)
80f6ad04e6Sjsg
81f6ad04e6Sjsg /* Watchdog interface */
82f6ad04e6Sjsg bus_space_tag_t sc_wdt_iot;
83f6ad04e6Sjsg bus_space_handle_t sc_wdt_ioh;
84f6ad04e6Sjsg
85f6ad04e6Sjsg int sc_wdt_period;
8618078679Skettenis
8718078679Skettenis /* High Precision Event Timer */
8818078679Skettenis bus_space_tag_t sc_hpet_iot;
8918078679Skettenis bus_space_handle_t sc_hpet_ioh;
9018078679Skettenis
9118078679Skettenis struct timecounter sc_hpet_timecounter;
92f6ad04e6Sjsg };
93f6ad04e6Sjsg
94f6ad04e6Sjsg struct cfdriver tcpcib_cd = {
95f6ad04e6Sjsg NULL, "tcpcib", DV_DULL
96f6ad04e6Sjsg };
97f6ad04e6Sjsg
98f6ad04e6Sjsg int tcpcib_match(struct device *, void *, void *);
99f6ad04e6Sjsg void tcpcib_attach(struct device *, struct device *, void *);
100f6ad04e6Sjsg int tcpcib_activate(struct device *, int);
101f6ad04e6Sjsg
102f6ad04e6Sjsg int tcpcib_wdt_cb(void *, int);
103f6ad04e6Sjsg void tcpcib_wdt_init(struct tcpcib_softc *, int);
104f6ad04e6Sjsg void tcpcib_wdt_start(struct tcpcib_softc *);
105f6ad04e6Sjsg void tcpcib_wdt_stop(struct tcpcib_softc *);
106f6ad04e6Sjsg
10718078679Skettenis u_int tcpcib_hpet_get_timecount(struct timecounter *tc);
10818078679Skettenis
109*8d2c75e4Smpi const struct cfattach tcpcib_ca = {
110f6ad04e6Sjsg sizeof(struct tcpcib_softc), tcpcib_match, tcpcib_attach,
111f6ad04e6Sjsg NULL, tcpcib_activate
112f6ad04e6Sjsg };
113f6ad04e6Sjsg
114f6ad04e6Sjsg /* from arch/<*>/pci/pcib.c */
115f6ad04e6Sjsg void pcibattach(struct device *parent, struct device *self, void *aux);
116f6ad04e6Sjsg
117f6ad04e6Sjsg const struct pci_matchid tcpcib_devices[] = {
118f6ad04e6Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_E600_LPC }
119f6ad04e6Sjsg };
120f6ad04e6Sjsg
121f6ad04e6Sjsg static __inline void
tcpcib_wdt_unlock(struct tcpcib_softc * sc)122f6ad04e6Sjsg tcpcib_wdt_unlock(struct tcpcib_softc *sc)
123f6ad04e6Sjsg {
124f6ad04e6Sjsg /* Register unlocking sequence */
125f6ad04e6Sjsg bus_space_write_1(sc->sc_wdt_iot, sc->sc_wdt_ioh, E600_WDT_RR0, 0x80);
126f6ad04e6Sjsg bus_space_write_1(sc->sc_wdt_iot, sc->sc_wdt_ioh, E600_WDT_RR0, 0x86);
127f6ad04e6Sjsg }
128f6ad04e6Sjsg
129f6ad04e6Sjsg void
tcpcib_wdt_init(struct tcpcib_softc * sc,int period)130f6ad04e6Sjsg tcpcib_wdt_init(struct tcpcib_softc *sc, int period)
131f6ad04e6Sjsg {
132f6ad04e6Sjsg u_int32_t preload;
133f6ad04e6Sjsg
134f6ad04e6Sjsg /* Set new timeout */
135f6ad04e6Sjsg preload = (period * 33000000) >> 15;
136f6ad04e6Sjsg preload--;
137f6ad04e6Sjsg
138f6ad04e6Sjsg /*
139f6ad04e6Sjsg * Set watchdog to perform a cold reset toggling the GPIO pin and the
140f6ad04e6Sjsg * prescaler set to 1ms-10m resolution
141f6ad04e6Sjsg */
142f6ad04e6Sjsg bus_space_write_1(sc->sc_wdt_iot, sc->sc_wdt_ioh, E600_WDT_WDTCR,
143f6ad04e6Sjsg E600_WDT_WDTCR_ENABLE);
144f6ad04e6Sjsg tcpcib_wdt_unlock(sc);
145f6ad04e6Sjsg bus_space_write_4(sc->sc_wdt_iot, sc->sc_wdt_ioh, E600_WDT_PV1, 0);
146f6ad04e6Sjsg tcpcib_wdt_unlock(sc);
147f6ad04e6Sjsg bus_space_write_4(sc->sc_wdt_iot, sc->sc_wdt_ioh, E600_WDT_PV2,
148f6ad04e6Sjsg preload);
149f6ad04e6Sjsg tcpcib_wdt_unlock(sc);
150f6ad04e6Sjsg bus_space_write_1(sc->sc_wdt_iot, sc->sc_wdt_ioh, E600_WDT_RR1,
151f6ad04e6Sjsg E600_WDT_RR1_RELOAD);
152f6ad04e6Sjsg }
153f6ad04e6Sjsg
154f6ad04e6Sjsg void
tcpcib_wdt_start(struct tcpcib_softc * sc)155f6ad04e6Sjsg tcpcib_wdt_start(struct tcpcib_softc *sc)
156f6ad04e6Sjsg {
157f6ad04e6Sjsg /* Enable watchdog */
158f6ad04e6Sjsg bus_space_write_1(sc->sc_wdt_iot, sc->sc_wdt_ioh, E600_WDT_WDTLR,
159f6ad04e6Sjsg E600_WDT_WDTLR_ENABLE);
160f6ad04e6Sjsg }
161f6ad04e6Sjsg
162f6ad04e6Sjsg void
tcpcib_wdt_stop(struct tcpcib_softc * sc)163f6ad04e6Sjsg tcpcib_wdt_stop(struct tcpcib_softc *sc)
164f6ad04e6Sjsg {
165f6ad04e6Sjsg /* Disable watchdog, with a reload before for safety */
166f6ad04e6Sjsg tcpcib_wdt_unlock(sc);
167f6ad04e6Sjsg bus_space_write_1(sc->sc_wdt_iot, sc->sc_wdt_ioh, E600_WDT_RR1,
168f6ad04e6Sjsg E600_WDT_RR1_RELOAD);
169f6ad04e6Sjsg bus_space_write_1(sc->sc_wdt_iot, sc->sc_wdt_ioh, E600_WDT_WDTLR, 0);
170f6ad04e6Sjsg }
171f6ad04e6Sjsg
172f6ad04e6Sjsg int
tcpcib_match(struct device * parent,void * match,void * aux)173f6ad04e6Sjsg tcpcib_match(struct device *parent, void *match, void *aux)
174f6ad04e6Sjsg {
175f6ad04e6Sjsg if (pci_matchbyid((struct pci_attach_args *)aux, tcpcib_devices,
176f6ad04e6Sjsg sizeof(tcpcib_devices) / sizeof(tcpcib_devices[0])))
177f6ad04e6Sjsg return (2);
178f6ad04e6Sjsg
179f6ad04e6Sjsg return (0);
180f6ad04e6Sjsg }
181f6ad04e6Sjsg
182f6ad04e6Sjsg void
tcpcib_attach(struct device * parent,struct device * self,void * aux)183f6ad04e6Sjsg tcpcib_attach(struct device *parent, struct device *self, void *aux)
184f6ad04e6Sjsg {
185f6ad04e6Sjsg struct tcpcib_softc *sc = (struct tcpcib_softc *)self;
186f6ad04e6Sjsg struct pci_attach_args *pa = aux;
18718078679Skettenis struct timecounter *tc = &sc->sc_hpet_timecounter;
188f6ad04e6Sjsg u_int32_t reg, wdtbase;
189f6ad04e6Sjsg
190f6ad04e6Sjsg sc->sc_active = 0;
191f6ad04e6Sjsg
19218078679Skettenis /* High Precision Event Timer */
19318078679Skettenis sc->sc_hpet_iot = pa->pa_memt;
19418078679Skettenis if (bus_space_map(sc->sc_hpet_iot, E600_HPET_BASE, E600_HPET_SIZE, 0,
19518078679Skettenis &sc->sc_hpet_ioh) == 0) {
19618078679Skettenis tc->tc_get_timecount = tcpcib_hpet_get_timecount;
19718078679Skettenis /* XXX 64-bit counter is not supported! */
19818078679Skettenis tc->tc_counter_mask = 0xffffffff;
19918078679Skettenis
20018078679Skettenis reg = bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
20118078679Skettenis E600_HPET_PERIOD);
20218078679Skettenis /* femtosecs -> Hz */
20318078679Skettenis tc->tc_frequency = 1000000000000000ULL / reg;
20418078679Skettenis
20518078679Skettenis tc->tc_name = sc->sc_dev.dv_xname;
20618078679Skettenis tc->tc_quality = 2000;
20718078679Skettenis tc->tc_priv = sc;
20818078679Skettenis tc_init(tc);
20918078679Skettenis
21018078679Skettenis /* Enable counting */
21118078679Skettenis bus_space_write_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
21218078679Skettenis E600_HPET_GC, E600_HPET_GC_ENABLE);
21318078679Skettenis
21418078679Skettenis sc->sc_active |= E600_HPET_ACTIVE;
21518078679Skettenis
21618078679Skettenis printf(": %llu Hz timer", tc->tc_frequency);
21718078679Skettenis }
21818078679Skettenis
219f6ad04e6Sjsg /* Map Watchdog I/O space */
220f6ad04e6Sjsg reg = pci_conf_read(pa->pa_pc, pa->pa_tag, E600_LPC_WDTBA);
221f6ad04e6Sjsg wdtbase = reg & 0xffff;
222f6ad04e6Sjsg sc->sc_wdt_iot = pa->pa_iot;
22361e87b28Sderaadt if (reg & (1U << 31) && wdtbase) {
224f6ad04e6Sjsg if (PCI_MAPREG_IO_ADDR(wdtbase) == 0 ||
225f6ad04e6Sjsg bus_space_map(sc->sc_wdt_iot, PCI_MAPREG_IO_ADDR(wdtbase),
226f6ad04e6Sjsg E600_WDT_SIZE, 0, &sc->sc_wdt_ioh)) {
22718078679Skettenis printf("%c can't map watchdog I/O space",
22818078679Skettenis sc->sc_active ? ',' : ':');
229f6ad04e6Sjsg goto corepcib;
230f6ad04e6Sjsg }
23118078679Skettenis printf("%c watchdog", sc->sc_active ? ',' : ':');
232f6ad04e6Sjsg
233f6ad04e6Sjsg /* Check for reboot on timeout */
234f6ad04e6Sjsg reg = bus_space_read_1(sc->sc_wdt_iot, sc->sc_wdt_ioh,
235f6ad04e6Sjsg E600_WDT_RR1);
236f6ad04e6Sjsg if (reg & E600_WDT_RR1_TIMEOUT) {
237f6ad04e6Sjsg printf(", reboot on timeout");
238f6ad04e6Sjsg
239f6ad04e6Sjsg /* Clear timeout bit */
240f6ad04e6Sjsg tcpcib_wdt_unlock(sc);
241f6ad04e6Sjsg bus_space_write_1(sc->sc_wdt_iot, sc->sc_wdt_ioh,
242f6ad04e6Sjsg E600_WDT_RR1, E600_WDT_RR1_TIMEOUT);
243f6ad04e6Sjsg }
244f6ad04e6Sjsg
245f6ad04e6Sjsg /* Check it's not locked already */
246f6ad04e6Sjsg reg = bus_space_read_1(sc->sc_wdt_iot, sc->sc_wdt_ioh,
247f6ad04e6Sjsg E600_WDT_WDTLR);
248f6ad04e6Sjsg if (reg & E600_WDT_WDTLR_LOCK) {
249f6ad04e6Sjsg printf(", locked");
250f6ad04e6Sjsg goto corepcib;
251f6ad04e6Sjsg }
252f6ad04e6Sjsg
253f6ad04e6Sjsg /* Disable watchdog */
254f6ad04e6Sjsg tcpcib_wdt_stop(sc);
255f6ad04e6Sjsg sc->sc_wdt_period = 0;
256f6ad04e6Sjsg
257f6ad04e6Sjsg sc->sc_active |= E600_WDT_ACTIVE;
258f6ad04e6Sjsg
259f6ad04e6Sjsg /* Register new watchdog */
2602bc62decSderaadt wdog_register(tcpcib_wdt_cb, sc);
261f6ad04e6Sjsg }
262f6ad04e6Sjsg
263f6ad04e6Sjsg corepcib:
264f6ad04e6Sjsg /* Provide core pcib(4) functionality */
265f6ad04e6Sjsg pcibattach(parent, self, aux);
266f6ad04e6Sjsg }
267f6ad04e6Sjsg
268f6ad04e6Sjsg int
tcpcib_activate(struct device * self,int act)269f6ad04e6Sjsg tcpcib_activate(struct device *self, int act)
270f6ad04e6Sjsg {
271f6ad04e6Sjsg struct tcpcib_softc *sc = (struct tcpcib_softc *)self;
27237ecb596Sderaadt int rv = 0;
273f6ad04e6Sjsg
274f6ad04e6Sjsg switch (act) {
275f6ad04e6Sjsg case DVACT_SUSPEND:
27637ecb596Sderaadt rv = config_activate_children(self, act);
277f6ad04e6Sjsg /* Watchdog is running, disable it */
278f6ad04e6Sjsg if (sc->sc_active & E600_WDT_ACTIVE && sc->sc_wdt_period != 0)
279f6ad04e6Sjsg tcpcib_wdt_stop(sc);
280f6ad04e6Sjsg break;
281f6ad04e6Sjsg case DVACT_RESUME:
282f6ad04e6Sjsg if (sc->sc_active & E600_WDT_ACTIVE) {
283f6ad04e6Sjsg /*
284f6ad04e6Sjsg * Watchdog was running prior to suspend so reenable
285f6ad04e6Sjsg * it, otherwise make sure it stays disabled
286f6ad04e6Sjsg */
287f6ad04e6Sjsg if (sc->sc_wdt_period != 0) {
288f6ad04e6Sjsg tcpcib_wdt_init(sc, sc->sc_wdt_period);
289f6ad04e6Sjsg tcpcib_wdt_start(sc);
290f6ad04e6Sjsg } else
291f6ad04e6Sjsg tcpcib_wdt_stop(sc);
292f6ad04e6Sjsg }
29318078679Skettenis if (sc->sc_active & E600_HPET_ACTIVE)
29418078679Skettenis bus_space_write_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
29518078679Skettenis E600_HPET_GC, E600_HPET_GC_ENABLE);
29637ecb596Sderaadt rv = config_activate_children(self, act);
297c06fda6dSderaadt break;
2983b06f262Smikeb case DVACT_POWERDOWN:
2993b06f262Smikeb if (sc->sc_active & E600_WDT_ACTIVE)
3003b06f262Smikeb wdog_shutdown(self);
3013b06f262Smikeb rv = config_activate_children(self, act);
3023b06f262Smikeb break;
303c06fda6dSderaadt default:
30437ecb596Sderaadt rv = config_activate_children(self, act);
305f6ad04e6Sjsg break;
306f6ad04e6Sjsg }
30737ecb596Sderaadt return (rv);
308f6ad04e6Sjsg }
309f6ad04e6Sjsg
310f6ad04e6Sjsg int
tcpcib_wdt_cb(void * arg,int period)311f6ad04e6Sjsg tcpcib_wdt_cb(void *arg, int period)
312f6ad04e6Sjsg {
313f6ad04e6Sjsg struct tcpcib_softc *sc = arg;
314f6ad04e6Sjsg
315f6ad04e6Sjsg if (period == 0) {
316f6ad04e6Sjsg if (sc->sc_wdt_period != 0)
317f6ad04e6Sjsg tcpcib_wdt_stop(sc);
318f6ad04e6Sjsg } else {
319f6ad04e6Sjsg /* 600 seconds is the maximum supported timeout value */
320f6ad04e6Sjsg if (period > 600)
321f6ad04e6Sjsg period = 600;
322f6ad04e6Sjsg if (sc->sc_wdt_period != period)
323f6ad04e6Sjsg tcpcib_wdt_init(sc, period);
324f6ad04e6Sjsg if (sc->sc_wdt_period == 0) {
325f6ad04e6Sjsg tcpcib_wdt_start(sc);
326f6ad04e6Sjsg } else {
327f6ad04e6Sjsg /* Reset timer */
328f6ad04e6Sjsg tcpcib_wdt_unlock(sc);
329f6ad04e6Sjsg bus_space_write_1(sc->sc_wdt_iot, sc->sc_wdt_ioh,
330f6ad04e6Sjsg E600_WDT_RR1, E600_WDT_RR1_RELOAD);
331f6ad04e6Sjsg }
332f6ad04e6Sjsg }
333f6ad04e6Sjsg sc->sc_wdt_period = period;
334f6ad04e6Sjsg
335f6ad04e6Sjsg return (period);
336f6ad04e6Sjsg }
33718078679Skettenis
33818078679Skettenis u_int
tcpcib_hpet_get_timecount(struct timecounter * tc)33918078679Skettenis tcpcib_hpet_get_timecount(struct timecounter *tc)
34018078679Skettenis {
34118078679Skettenis struct tcpcib_softc *sc = tc->tc_priv;
34218078679Skettenis
34318078679Skettenis /* XXX 64-bit counter is not supported! */
34418078679Skettenis return bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
34518078679Skettenis E600_HPET_MCV);
34618078679Skettenis }
347