]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/IA32_flat_GCC_Galileo_Gen_2/Support_Files/GPIO_I2C.c
commit 9f316c246baafa15c542a5aea81a94f26e3d6507
[freertos] / FreeRTOS / Demo / IA32_flat_GCC_Galileo_Gen_2 / Support_Files / GPIO_I2C.c
1 /*--------------------------------------------------------------------\r
2  Copyright(c) 2015 Intel Corporation. All rights reserved.\r
3 \r
4  Redistribution and use in source and binary forms, with or without\r
5  modification, are permitted provided that the following conditions\r
6  are met:\r
7 \r
8  * Redistributions of source code must retain the above copyright\r
9  notice, this list of conditions and the following disclaimer.\r
10  * Redistributions in binary form must reproduce the above copyright\r
11  notice, this list of conditions and the following disclaimer in\r
12  the documentation and/or other materials provided with the\r
13  distribution.\r
14  * Neither the name of Intel Corporation nor the names of its\r
15  contributors may be used to endorse or promote products derived\r
16  from this software without specific prior written permission.\r
17 \r
18  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
19  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
20  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
21  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\r
22  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
23  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
24  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
25  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
26  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
27  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r
28  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
29  --------------------------------------------------------------------*/\r
30 \r
31 /*-----------------------------------------------------------------------\r
32  * Any required includes\r
33  *------------------------------------------------------------------------\r
34  */\r
35 #include "GPIO_I2C.h"\r
36 \r
37 /*-----------------------------------------------------------------------\r
38  * Any required local definitions\r
39  *------------------------------------------------------------------------\r
40  */\r
41 #ifndef NULL\r
42         #define NULL (void *)0\r
43 #endif\r
44 /*-----------------------------------------------------------------------\r
45  * Function prototypes\r
46  *------------------------------------------------------------------------\r
47  */\r
48 static void vGalileoRouteLEDPins(void);\r
49 \r
50 /*-----------------------------------------------------------------------\r
51  * Static variables\r
52  *------------------------------------------------------------------------\r
53  */\r
54 static struct BOARD_GPIO_CONTROLLER_CONFIG GpioConfig;\r
55 static struct BOARD_LEGACY_GPIO_CONFIG LegacyGpioConfig;\r
56 \r
57 static uint32_t LegacyGpioBase = 0;\r
58 static uint32_t IohGpioBase = 0;\r
59 static uint32_t I2CGpioBase = 0;\r
60 \r
61 static uint32_t bGalileoGPIOInitialized = FALSE;\r
62 \r
63 /*-----------------------------------------------------------------------\r
64  * GPIO support functions\r
65  *------------------------------------------------------------------------\r
66  */\r
67  static uint32_t pciIOread32(uint32_t addr)\r
68  {\r
69           outl(IO_PCI_ADDRESS_PORT, addr);\r
70           uint32_t data = inl(IO_PCI_DATA_PORT);\r
71           return data;\r
72  }\r
73  /*-----------------------------------------------------------*/\r
74 \r
75  static void pciIOwrite32(uint32_t addr, uint32_t IO_data)\r
76  {\r
77          outl(IO_PCI_ADDRESS_PORT, addr);\r
78          outl(IO_PCI_DATA_PORT, IO_data );\r
79  }\r
80  /*-----------------------------------------------------------*/\r
81 \r
82  static int32_t uiGalileoGPIORead(uint32_t Offset, uint8_t UseMask)\r
83  {\r
84          // Keep reserved bits [31:8]\r
85          if (UseMask)\r
86                  return *((volatile uint32_t *) (uintn_t)(IohGpioBase + Offset)) & 0xFFFFFF00;\r
87          else\r
88                  return *((volatile uint32_t *) (uintn_t)(IohGpioBase + Offset));\r
89  }\r
90  /*-----------------------------------------------------------*/\r
91 \r
92  static void vGalileoGPIOWrite(uint32_t Offset, uint32_t WriteData32)\r
93  {\r
94          uint32_t Data32 = uiGalileoGPIORead(Offset, true);\r
95      if (Offset !=  GPIO_INTSTATUS)\r
96          Data32 |= (WriteData32 & 0x000FFFFF);\r
97      *((volatile uint32_t *) (uintn_t)(IohGpioBase + Offset)) = Data32;\r
98  }\r
99  /*-----------------------------------------------------------*/\r
100 \r
101  static int32_t uiGalileoLegacyGPIOPCIRead(uint32_t addr, uint32_t Mask)\r
102  {\r
103          // Keep reserved bits (Mask Varies)\r
104          return pciIOread32(addr) & Mask;\r
105  }\r
106  /*-----------------------------------------------------------*/\r
107 \r
108  static void vGalileoLegacyGPIOPCIWrite(uint32_t addr, uint32_t WriteData32, uint32_t Mask)\r
109  {\r
110          uint32_t Data32 = uiGalileoLegacyGPIOPCIRead(addr, Mask);\r
111      Data32 |= (WriteData32 & ~Mask);\r
112      pciIOwrite32(addr, Data32);\r
113  }\r
114  /*-----------------------------------------------------------*/\r
115 \r
116  static int32_t uiGalileoLegacyGPIOPortRead(uint32_t addr, uint32_t Mask)\r
117  {\r
118          // Keep reserved bits (Mask Varies)\r
119          return inl(addr) & Mask;\r
120  }\r
121  /*-----------------------------------------------------------*/\r
122 \r
123  static void vGalileoLegacyGPIOPortRMW(uint32_t addr, uint32_t WriteData32, uint32_t Mask)\r
124  {\r
125          uint32_t Data32 = uiGalileoLegacyGPIOPortRead(addr, Mask);\r
126      Data32 |= (WriteData32 & ~Mask);\r
127      outl(addr, Data32);\r
128  }\r
129  /*-----------------------------------------------------------*/\r
130 \r
131  /*-----------------------------------------------------------------------\r
132   * Controller initialization functions\r
133   *------------------------------------------------------------------------\r
134   */\r
135  void vGalileoInitializeLegacyGPIO(void)\r
136  {\r
137          // Read Register Default Values into Structure\r
138          struct BOARD_LEGACY_GPIO_CONFIG LegacyGPIOConfigTable[] =\r
139          { PLATFORM_LEGACY_GPIO_CONFIG_DEFINITION };\r
140 \r
141          // BDF for Legacy GPIO (from the Quark Datasheet)\r
142          uint8_t Bus = LEGACY_GPIO_BUS_NUMBER;\r
143          uint8_t Device = LEGACY_GPIO_DEVICE_NUMBER;\r
144          uint8_t Func = LEGACY_GPIO_FUNCTION_NUMBER;\r
145 \r
146          // Get PCI Configuration IO Address\r
147          LegacyGpioBase =\r
148          uiGalileoLegacyGPIOPCIRead(IO_PCI_ADDRESS(Bus, Device, Func, R_QNC_LPC_GBA_BASE), B_QNC_LPC_GPA_BASE_MASK);\r
149 \r
150          // Quiet compiler by doing a legacy GPIO write\r
151          uint32_t PciCmd = uiGalileoLegacyGPIOPCIRead((LegacyGpioBase + PCI_REG_PCICMD), 0xFFFFFFFF);\r
152          vGalileoLegacyGPIOPCIWrite((LegacyGpioBase + PCI_REG_PCICMD), (PciCmd | 0x7), 0xFFFFFFFF);\r
153 \r
154          // Setup Structure\r
155          LegacyGpioConfig = LegacyGPIOConfigTable[0];\r
156 \r
157          // Update values\r
158          vGalileoLegacyGPIOPortRMW(LegacyGpioBase + R_QNC_GPIO_CGEN_CORE_WELL, LegacyGpioConfig.CoreWellEnable, 0xFFFFFFFC);\r
159          vGalileoLegacyGPIOPortRMW(LegacyGpioBase + R_QNC_GPIO_CGIO_CORE_WELL, LegacyGpioConfig.CoreWellIoSelect, 0xFFFFFFFC);\r
160          vGalileoLegacyGPIOPortRMW(LegacyGpioBase + R_QNC_GPIO_CGLVL_CORE_WELL, LegacyGpioConfig.CoreWellLvlForInputOrOutput, 0xFFFFFFFC);\r
161          vGalileoLegacyGPIOPortRMW(LegacyGpioBase + R_QNC_GPIO_CGTPE_CORE_WELL, LegacyGpioConfig.CoreWellTriggerPositiveEdge, 0xFFFFFFFC);\r
162          vGalileoLegacyGPIOPortRMW(LegacyGpioBase + R_QNC_GPIO_CGTNE_CORE_WELL, LegacyGpioConfig.CoreWellTriggerNegativeEdge, 0xFFFFFFFC);\r
163          vGalileoLegacyGPIOPortRMW(LegacyGpioBase + R_QNC_GPIO_CGGPE_CORE_WELL, LegacyGpioConfig.ResumeWellGPEEnable, 0xFFFFFFFC);\r
164          vGalileoLegacyGPIOPortRMW(LegacyGpioBase + R_QNC_GPIO_CGSMI_CORE_WELL, LegacyGpioConfig.ResumeWellSMIEnable, 0xFFFFFFFC);\r
165          vGalileoLegacyGPIOPortRMW(LegacyGpioBase + R_QNC_GPIO_CGEN_CORE_WELL, LegacyGpioConfig.CoreWellTriggerStatus, 0xFFFFFFFC);\r
166          vGalileoLegacyGPIOPortRMW(LegacyGpioBase + R_QNC_GPIO_CNMIEN_CORE_WELL, LegacyGpioConfig.ResumeWellNMIEnable, 0xFFFFFFFC);\r
167          vGalileoLegacyGPIOPortRMW(LegacyGpioBase + R_QNC_GPIO_RGEN_RESUME_WELL, LegacyGpioConfig.ResumeWellEnable, 0xFFFFFFC0);\r
168          vGalileoLegacyGPIOPortRMW(LegacyGpioBase + R_QNC_GPIO_RGIO_RESUME_WELL, LegacyGpioConfig.ResumeWellIoSelect, 0xFFFFFFC0);\r
169          vGalileoLegacyGPIOPortRMW(LegacyGpioBase + R_QNC_GPIO_RGLVL_RESUME_WELL, LegacyGpioConfig.ResumeWellLvlForInputOrOutput, 0xFFFFFFC0);\r
170          vGalileoLegacyGPIOPortRMW(LegacyGpioBase + R_QNC_GPIO_RGTPE_RESUME_WELL, LegacyGpioConfig.ResumeWellTriggerPositiveEdge, 0xFFFFFFC0);\r
171          vGalileoLegacyGPIOPortRMW(LegacyGpioBase + R_QNC_GPIO_RGTNE_RESUME_WELL, LegacyGpioConfig.ResumeWellTriggerNegativeEdge, 0xFFFFFFC0);\r
172          vGalileoLegacyGPIOPortRMW(LegacyGpioBase + R_QNC_GPIO_RGGPE_RESUME_WELL, LegacyGpioConfig.CoreWellGPEEnable, 0xFFFFFFC0);\r
173          vGalileoLegacyGPIOPortRMW(LegacyGpioBase + R_QNC_GPIO_RGSMI_RESUME_WELL, LegacyGpioConfig.CoreWellSMIEnable, 0xFFFFFFC0);\r
174          vGalileoLegacyGPIOPortRMW(LegacyGpioBase + R_QNC_GPIO_RGTS_RESUME_WELL, LegacyGpioConfig.ResumeWellTriggerStatus, 0xFFFFFFC0);\r
175          vGalileoLegacyGPIOPortRMW(LegacyGpioBase + R_QNC_GPIO_RNMIEN_RESUME_WELL, LegacyGpioConfig.CoreWellNMIEnable, 0xFFFFFFC0);\r
176  }\r
177  /*-----------------------------------------------------------*/\r
178 \r
179  void vGalileoInitializeGpioController(void)\r
180  {\r
181          // Read Register Default Values into Structure\r
182          struct BOARD_GPIO_CONTROLLER_CONFIG BoardGpioControllerConfigTable[] =\r
183          { PLATFORM_GPIO_CONTROLLER_CONFIG_DEFINITION };\r
184 \r
185          // BDF for I2C Controller (from the Quark Datasheet)\r
186          uint8_t Bus = IOH_I2C_GPIO_BUS_NUMBER;\r
187          uint8_t Device = IOH_I2C_GPIO_DEVICE_NUMBER;\r
188          uint8_t Func = IOH_I2C_GPIO_FUNCTION_NUMBER;\r
189 \r
190          // Get PCI Configuration MMIO Address\r
191          uint32_t gpio_controller_base = MMIO_PCI_ADDRESS(Bus, Device, Func, 0);\r
192 \r
193          // Get Vendor and Device IDs\r
194          uint16_t PciVid = mem_read(gpio_controller_base, PCI_REG_VID, 2);\r
195          uint16_t PciDid = mem_read(gpio_controller_base, PCI_REG_DID, 2);\r
196 \r
197          // Check for valid VID and DID\r
198          if((PciVid == V_IOH_I2C_GPIO_VENDOR_ID) && (PciDid == V_IOH_I2C_GPIO_DEVICE_ID))\r
199          {\r
200                  // Read PCICMD\r
201                  uint8_t PciCmd = mem_read(gpio_controller_base, PCI_REG_PCICMD, 1);\r
202                  // Enable Bus Master(Bit2), MMIO Space(Bit1) & I/O Space(Bit0)\r
203                  mem_write(gpio_controller_base, PCI_REG_PCICMD, 1, (PciCmd | 0x7));\r
204                  // Read MEM_BASE\r
205                  IohGpioBase = mem_read(gpio_controller_base, R_IOH_GPIO_MEMBAR, 4);\r
206                  // Setup Structure\r
207                  GpioConfig = BoardGpioControllerConfigTable[0];\r
208                  // IEN- Interrupt Enable Register\r
209                  vGalileoGPIOWrite(GPIO_INTEN, GpioConfig.IntEn);\r
210                  // ISTATUS- Interrupt Status Register\r
211                  vGalileoGPIOWrite(GPIO_INTSTATUS, 0);\r
212                  // GPIO SWPORTA Data Register - GPIO_SWPORTA_DR\r
213                  vGalileoGPIOWrite(GPIO_SWPORTA_DR, GpioConfig.PortADR);\r
214                  // GPIO SWPORTA Data Direction Register - GPIO_SWPORTA_DDR\r
215                  vGalileoGPIOWrite(GPIO_SWPORTA_DDR, GpioConfig.PortADir);\r
216                  // Interrupt Mask Register - GPIO_INTMASK\r
217                  vGalileoGPIOWrite(GPIO_INTMASK, GpioConfig.IntMask);\r
218                  // Interrupt Level Type Register - GPIO_INTTYPE_LEVEL\r
219                  vGalileoGPIOWrite(GPIO_INTTYPE_LEVEL, GpioConfig.IntType);\r
220                  // Interrupt Polarity Type Register - GPIO_INT_POLARITY\r
221                  vGalileoGPIOWrite(GPIO_INT_POLARITY, GpioConfig.IntPolarity);\r
222                  // Interrupt Debounce Type Register - GPIO_DEBOUNCE\r
223                  vGalileoGPIOWrite(GPIO_DEBOUNCE, GpioConfig.Debounce);\r
224                  // Interrupt Clock Synchronization Register - GPIO_LS_SYNC\r
225                  vGalileoGPIOWrite(GPIO_LS_SYNC, GpioConfig.LsSync);\r
226                  bGalileoGPIOInitialized = true;\r
227          }\r
228  }\r
229  /*-----------------------------------------------------------*/\r
230 \r
231  /*-----------------------------------------------------------------------\r
232   * I/O direction and level setting functions\r
233   *------------------------------------------------------------------------\r
234   */\r
235   void vGalileoSetGPIOBitDirection(uint32_t GPIONumber, uint32_t Direction)\r
236   {\r
237           /* Check Range. */\r
238           if(GPIONumber <= 9)\r
239           {\r
240                   /* setup gpio direction. */\r
241                   if (bGalileoGPIOInitialized)\r
242                   {\r
243                           if(Direction == GPIO_OUTPUT)\r
244                                   GpioConfig.PortADir |= (1 << GPIONumber);\r
245                           else\r
246                                   GpioConfig.PortADir &= ~(1 << GPIONumber);\r
247                           vGalileoGPIOWrite(GPIO_SWPORTA_DDR, GpioConfig.PortADir);\r
248                   }\r
249           }\r
250   }\r
251   /*-----------------------------------------------------------*/\r
252 \r
253   void vGalileoSetGPIOBitLevel(uint32_t GPIONumber, uint32_t Level)\r
254   {\r
255           /* Check Range. */\r
256           if(GPIONumber <= 9)\r
257           {\r
258                   /* Set the bit high or low. */\r
259                   if (bGalileoGPIOInitialized)\r
260                   {\r
261                           // 1 for on, 0 for off.\r
262                           if (Level == HIGH)\r
263                                   GpioConfig.PortADR |= (1 << GPIONumber);\r
264                           else\r
265                                   GpioConfig.PortADR &= ~(1 << GPIONumber);\r
266                           vGalileoGPIOWrite(GPIO_SWPORTA_DR, GpioConfig.PortADR);\r
267                   }\r
268           }\r
269   }\r
270   /*-----------------------------------------------------------*/\r
271 \r
272   static void LegacyGpioSetLevel(uint32_t RegOffset, uint32_t GpioNum, uint8_t HighLevel)\r
273   {\r
274           uint32_t RegValue;\r
275           uint32_t legacy_gpio_base;\r
276           uint32_t GpioNumMask;\r
277           uint8_t Bus = LEGACY_GPIO_BUS_NUMBER;\r
278           uint8_t Device = LEGACY_GPIO_DEVICE_NUMBER;\r
279           uint8_t Func = LEGACY_GPIO_FUNCTION_NUMBER;\r
280 \r
281           // Get PCI Configuration IO Address\r
282           legacy_gpio_base =\r
283           uiGalileoLegacyGPIOPCIRead(IO_PCI_ADDRESS(Bus, Device, Func, R_QNC_LPC_GBA_BASE), B_QNC_LPC_GPA_BASE_MASK);\r
284 \r
285           // Read register (Port I/O )\r
286           RegValue = inl(legacy_gpio_base + RegOffset);\r
287 \r
288           // Set Data and mask\r
289           GpioNumMask = (1 << GpioNum);\r
290           if (HighLevel)\r
291                   RegValue |= (GpioNumMask);\r
292           else\r
293                   RegValue &= ~(GpioNumMask);\r
294 \r
295           // Write the data (Port I/O )\r
296           outl((legacy_gpio_base + RegOffset), RegValue);\r
297   }\r
298   /*-----------------------------------------------------------*/\r
299 \r
300   void vGalileoLegacyGPIOInitializationForLED(void)\r
301   {\r
302           // Setup multiplexers to route GPIO_SUS<5> to LED\r
303           vGalileoRouteLEDPins();\r
304 \r
305           // Set GPIO_SUS<5> as output\r
306           LegacyGpioSetLevel (R_QNC_GPIO_RGIO_RESUME_WELL,\r
307           GALILEO_GEN2_FLASH_UPDATE_LED_RESUMEWELL_GPIO, GPIO_OUTPUT);\r
308 \r
309           // Set GPIO_SUS<5> level to low\r
310           LegacyGpioSetLevel (R_QNC_GPIO_RGLVL_RESUME_WELL,\r
311       GALILEO_GEN2_FLASH_UPDATE_LED_RESUMEWELL_GPIO, LOW);\r
312   }\r
313   /*-----------------------------------------------------------*/\r
314 \r
315   void vGalileoBlinkLEDUsingLegacyGPIO(uint32_t Level)\r
316   {\r
317           LegacyGpioSetLevel (R_QNC_GPIO_RGLVL_RESUME_WELL,\r
318           GALILEO_GEN2_FLASH_UPDATE_LED_RESUMEWELL_GPIO, Level);\r
319   }\r
320   /*-----------------------------------------------------------*/\r
321 \r
322   /*-----------------------------------------------------------------------\r
323    * I2C support functions\r
324    *------------------------------------------------------------------------\r
325    */\r
326   static inline uint64_t rdtsc(void)\r
327   {\r
328       uint32_t lo, hi;\r
329       uint64_t tsc;\r
330       __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));\r
331       tsc = hi;\r
332       tsc <<= 32;\r
333       tsc |= lo;\r
334       return tsc;\r
335   }\r
336   /*-----------------------------------------------------------*/\r
337 \r
338   void vMicroSecondDelay(uint32_t DelayTime)\r
339   {\r
340           uint64_t diff_in_us = 0;\r
341           uint64_t cpufreq_in_mhz = 400;\r
342           uint64_t tsc_start = rdtsc();\r
343           uint64_t tsc_current = tsc_start;\r
344 \r
345           do\r
346           {\r
347                   diff_in_us = ((tsc_current - tsc_start) / cpufreq_in_mhz);\r
348                   tsc_current = rdtsc();\r
349           }\r
350           while (diff_in_us < (uint64_t) DelayTime);\r
351   }\r
352   /*-----------------------------------------------------------*/\r
353 \r
354   void vMilliSecondDelay(uint32_t DelayTime)\r
355   {\r
356           vMicroSecondDelay (DelayTime * 1000);\r
357   }\r
358   /*-----------------------------------------------------------*/\r
359 \r
360   static uintn_t GetI2CIoPortBaseAddress(void)\r
361   {\r
362           uint8_t Bus = IOH_I2C_GPIO_BUS_NUMBER;\r
363           uint8_t Device = IOH_I2C_GPIO_DEVICE_NUMBER;\r
364           int8_t Func = IOH_I2C_GPIO_FUNCTION_NUMBER;\r
365           uint32_t I2C_controller_base = MMIO_PCI_ADDRESS(Bus, Device, Func, 0);\r
366           uintn_t I2CIoPortBaseAddress = mem_read(I2C_controller_base, R_IOH_I2C_MEMBAR, 4);\r
367           return I2CIoPortBaseAddress;\r
368   }\r
369   /*-----------------------------------------------------------*/\r
370 \r
371   static void EnableI2CMmioSpace(void)\r
372   {\r
373           uint8_t Bus = IOH_I2C_GPIO_BUS_NUMBER;\r
374           uint8_t Device = IOH_I2C_GPIO_DEVICE_NUMBER;\r
375           uint8_t Func = IOH_I2C_GPIO_FUNCTION_NUMBER;\r
376           uint32_t I2C_controller_base = MMIO_PCI_ADDRESS(Bus, Device, Func, 0);\r
377           uint8_t PciCmd = mem_read(I2C_controller_base, PCI_REG_PCICMD, 1);\r
378           mem_write(I2C_controller_base, PCI_REG_PCICMD, 1, (PciCmd | 0x7));\r
379   }\r
380   /*-----------------------------------------------------------*/\r
381 \r
382   static void DisableI2CController(void)\r
383   {\r
384           uintn_t       I2CIoPortBaseAddress;\r
385           uint32_t      Addr;\r
386           uint32_t      Data;\r
387           uint8_t       PollCount = 0;\r
388 \r
389           // Get I2C Memory Mapped registers base address.\r
390           I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
391 \r
392           // Disable the I2C Controller by setting IC_ENABLE.ENABLE to zero\r
393           Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE;\r
394           Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
395           Data &= ~B_I2C_REG_ENABLE;\r
396           *((volatile uint32_t *) (uintn_t)(Addr)) = Data;\r
397 \r
398           // Read the IC_ENABLE_STATUS.IC_EN Bit to check if Controller is disabled\r
399           Data = 0xFF;\r
400           Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE_STATUS;\r
401           Data = *((volatile uint32_t *) (uintn_t)(Addr)) & I2C_REG_ENABLE_STATUS;\r
402           while (Data != 0)\r
403           {\r
404                   // Poll the IC_ENABLE_STATUS.IC_EN Bit to check if Controller is disabled, until timeout (TI2C_POLL*MAX_T_POLL_COUNT).\r
405                   if (++PollCount >= MAX_T_POLL_COUNT)\r
406                           break;\r
407                   vMicroSecondDelay(TI2C_POLL);\r
408                   Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
409                   Data &= I2C_REG_ENABLE_STATUS;\r
410           }\r
411 \r
412           // Read IC_CLR_INTR register to automatically clear the combined interrupt,\r
413           // all individual interrupts and the IC_TX_ABRT_SOURCE register.\r
414           if (PollCount < MAX_T_POLL_COUNT)\r
415           {\r
416                   Addr = I2CIoPortBaseAddress + I2C_REG_CLR_INT;\r
417                   Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
418           }\r
419   }\r
420   /*-----------------------------------------------------------*/\r
421 \r
422   static void EnableI2CController(void)\r
423   {\r
424           uintn_t   I2CIoPortBaseAddress;\r
425           uint32_t  Addr;\r
426           uint32_t  Data;\r
427 \r
428           // Get I2C Memory Mapped registers base address.\r
429           I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
430 \r
431           // Enable the I2C Controller by setting IC_ENABLE.ENABLE to 1\r
432           Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE;\r
433           Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
434           Data |= B_I2C_REG_ENABLE;\r
435           *((volatile uint32_t *) (uintn_t)(Addr)) = Data;\r
436 \r
437           // Clear overflow and abort error status bits before transactions.\r
438           Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_OVER;\r
439           Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
440           Addr = I2CIoPortBaseAddress + I2C_REG_CLR_TX_OVER;\r
441           Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
442           Addr = I2CIoPortBaseAddress + I2C_REG_CLR_TX_ABRT;\r
443           Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
444   }\r
445   /*-----------------------------------------------------------*/\r
446 \r
447   static uint32_t InitializeInternal(I2C_ADDR_MODE AddrMode)\r
448   {\r
449                 uintn_t   I2CIoPortBaseAddress;\r
450                 uintn_t   Addr;\r
451                 uint32_t  Data;\r
452                 uint32_t  Status = 0;\r
453 \r
454                 // Enable access to I2C Controller MMIO space.\r
455                 EnableI2CMmioSpace ();\r
456 \r
457                 // Disable I2C Controller initially\r
458                 DisableI2CController ();\r
459 \r
460                 // Get I2C Memory Mapped registers base address.\r
461                  I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
462 \r
463                 // Clear START_DET\r
464                 Addr = I2CIoPortBaseAddress + I2C_REG_CLR_START_DET;\r
465                 Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
466                 Data &= ~B_I2C_REG_CLR_START_DET;\r
467                 *((volatile uint32_t *) (uintn_t)(Addr)) = Data;\r
468 \r
469                 // Clear STOP_DET\r
470                 Addr = I2CIoPortBaseAddress + I2C_REG_CLR_STOP_DET;\r
471                 Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
472                 Data &= ~B_I2C_REG_CLR_STOP_DET;\r
473                 *((volatile uint32_t *) (uintn_t)(Addr)) = Data;\r
474 \r
475                 // Set addressing mode to user defined (7 or 10 bit) and\r
476                 // speed mode to that defined by PCD (standard mode default).\r
477                 Addr = I2CIoPortBaseAddress + I2C_REG_CON;\r
478                 Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
479 \r
480                 // Set Addressing Mode\r
481                 if (AddrMode == EfiI2CSevenBitAddrMode)\r
482                         Data &= ~B_I2C_REG_CON_10BITADD_MASTER;\r
483                 else\r
484                         Data |= B_I2C_REG_CON_10BITADD_MASTER;\r
485 \r
486                 // Set Speed Mode\r
487                 Data &= ~B_I2C_REG_CON_SPEED;\r
488 \r
489                 // Default to slow mode\r
490                 Data |= BIT1;\r
491                 *((volatile uint32_t *) (uintn_t)(Addr)) = Data;\r
492                 Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
493                 return Status;\r
494   }\r
495   /*-----------------------------------------------------------*/\r
496 \r
497   static void I2cEntry(uint16_t *SaveCmdPtr, uint32_t *SaveBar0Ptr)\r
498   {\r
499                 uint8_t Bus = IOH_I2C_GPIO_BUS_NUMBER;\r
500                 uint8_t Device = IOH_I2C_GPIO_DEVICE_NUMBER;\r
501                 uint8_t Func = IOH_I2C_GPIO_FUNCTION_NUMBER;\r
502                 uint32_t I2C_controller_base = MMIO_PCI_ADDRESS(Bus, Device, Func, 0);\r
503 \r
504                 I2CGpioBase = mem_read(I2C_controller_base, R_IOH_I2C_MEMBAR, 4);\r
505                 *SaveBar0Ptr = I2CGpioBase;\r
506                 if (((*SaveBar0Ptr) & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK) == 0)\r
507                 {\r
508                         mem_write(I2C_controller_base, R_IOH_I2C_MEMBAR, 4, IO_PCI_ADDRESS(Bus, Device, Func, 0));\r
509                         // also Save Cmd Register, Setup by InitializeInternal later during xfers.\r
510                         *SaveCmdPtr = mem_read(I2C_controller_base, PCI_REG_PCICMD, 1);\r
511                 }\r
512   }\r
513   /*-----------------------------------------------------------*/\r
514 \r
515   static void I2cExit(uint16_t SaveCmd, uint32_t SaveBar0)\r
516   {\r
517                 if ((SaveBar0 & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK) == 0)\r
518                 {\r
519                         uint8_t Bus = IOH_I2C_GPIO_BUS_NUMBER;\r
520                         uint8_t Device = IOH_I2C_GPIO_DEVICE_NUMBER;\r
521                         uint8_t Func = IOH_I2C_GPIO_FUNCTION_NUMBER;\r
522                         uint32_t I2C_controller_base = MMIO_PCI_ADDRESS(Bus, Device, Func, 0);\r
523                         mem_write(I2C_controller_base, PCI_REG_PCICMD, 1, SaveCmd);\r
524                         mem_write(I2C_controller_base, R_IOH_I2C_MEMBAR, 4, SaveBar0);\r
525                 }\r
526   }\r
527   /*-----------------------------------------------------------*/\r
528 \r
529   static uint32_t WaitForStopDet(void)\r
530   {\r
531                 uintn_t   I2CIoPortBaseAddress;\r
532                 uint32_t  Addr;\r
533                 uint32_t  Data;\r
534                 uint32_t  PollCount = 0;\r
535                 uint32_t  Status = 0;\r
536 \r
537                 // Get I2C Memory Mapped registers base address.\r
538                 I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
539 \r
540                 // Wait for STOP Detect.\r
541                 Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;\r
542                 do\r
543                 {\r
544                         Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
545                         if ((Data & I2C_REG_RAW_INTR_STAT_TX_ABRT) != 0)\r
546                         {\r
547                                 Status = -1;\r
548                                 break;\r
549                         }\r
550                         if ((Data & I2C_REG_RAW_INTR_STAT_TX_OVER) != 0)\r
551                         {\r
552                                 Status = -1;\r
553                                 break;\r
554                         }\r
555                         if ((Data & I2C_REG_RAW_INTR_STAT_RX_OVER) != 0)\r
556                         {\r
557                                 Status = -1;\r
558                                 break;\r
559                         }\r
560                         if ((Data & I2C_REG_RAW_INTR_STAT_STOP_DET) != 0)\r
561                         {\r
562                                   Status = 0;\r
563                                   break;\r
564                         }\r
565                         vMicroSecondDelay(TI2C_POLL);\r
566                         PollCount++;\r
567                         if (PollCount >= MAX_STOP_DET_POLL_COUNT)\r
568                         {\r
569                                   Status = -1;\r
570                                   break;\r
571                         }\r
572                 } while (TRUE);\r
573 \r
574                 return Status;\r
575   }\r
576   /*-----------------------------------------------------------*/\r
577 \r
578   uint32_t WriteMultipleByte(uintn_t I2CAddress, uint8_t *WriteBuffer, uintn_t Length)\r
579   {\r
580                 uintn_t   I2CIoPortBaseAddress;\r
581                 uintn_t   Index;\r
582                 uintn_t   Addr;\r
583                 uint32_t  Data;\r
584                 uint32_t  Status = 0;\r
585 \r
586                 if (Length > I2C_FIFO_SIZE)\r
587                         return -1;  // Routine does not handle xfers > fifo size.\r
588 \r
589                 I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
590 \r
591                 // Write to the IC_TAR register the address of the slave device to be addressed\r
592                 Addr = I2CIoPortBaseAddress + I2C_REG_TAR;\r
593                 Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
594                 Data &= ~B_I2C_REG_TAR;\r
595                 Data |= I2CAddress;\r
596                 *((volatile uint32_t *) (uintn_t)(Addr)) = Data;\r
597 \r
598                 // Enable the I2C Controller\r
599                 EnableI2CController ();\r
600 \r
601                 // Write the data and transfer direction to the IC_DATA_CMD register.\r
602                 // Also specify that transfer should be terminated by STOP condition.\r
603                 Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;\r
604                 for (Index = 0; Index < Length; Index++)\r
605                 {\r
606                           Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
607                           Data &= 0xFFFFFF00;\r
608                           Data |= (uint8_t)WriteBuffer[Index];\r
609                           Data &= ~B_I2C_REG_DATA_CMD_RW;\r
610                           if (Index == (Length-1))\r
611                                   Data |= B_I2C_REG_DATA_CMD_STOP;\r
612                           *((volatile uint32_t *) (uintn_t)(Addr)) = Data;\r
613                 }\r
614 \r
615                 // Wait for transfer completion\r
616                 Status = WaitForStopDet ();\r
617 \r
618                 // Ensure I2C Controller disabled.\r
619                 DisableI2CController ();\r
620 \r
621                 return Status;\r
622   }\r
623   /*-----------------------------------------------------------*/\r
624 \r
625  static void I2CWriteMultipleBytes(I2C_DEVICE_ADDRESS  SlaveAddress,\r
626  I2C_ADDR_MODE AddrMode, uintn_t *Length, void *Buffer)\r
627  {\r
628           uintn_t  I2CAddress;\r
629           uint16_t SaveCmd;\r
630           uint32_t SaveBar0;\r
631 \r
632           if (Buffer != NULL && Length != NULL)\r
633           {\r
634                   SaveCmd = 0;\r
635                   SaveBar0 = 0;\r
636                   I2cEntry (&SaveCmd, &SaveBar0);\r
637                   if (InitializeInternal(AddrMode) == 0)\r
638                   {\r
639                           I2CAddress = SlaveAddress.I2CDeviceAddress;\r
640                           WriteMultipleByte(I2CAddress, Buffer, (*Length));\r
641                   }\r
642                   I2cExit (SaveCmd, SaveBar0);\r
643           }\r
644  }\r
645  /*-----------------------------------------------------------*/\r
646 \r
647   uint32_t ReadMultipleByte(uintn_t I2CAddress, uint8_t *Buffer,\r
648   uintn_t WriteLength, uintn_t ReadLength)\r
649   {\r
650           uintn_t   I2CIoPortBaseAddress;\r
651           uintn_t   Index;\r
652           uintn_t   Addr;\r
653           uint32_t  Data;\r
654           uint8_t   PollCount;\r
655           uint32_t  Status;\r
656 \r
657           if (WriteLength > I2C_FIFO_SIZE || ReadLength > I2C_FIFO_SIZE)\r
658                   return -1;  // Routine does not handle xfers > fifo size.\r
659 \r
660           I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
661 \r
662           // Write to the IC_TAR register the address of the slave device to be addressed\r
663           Addr = I2CIoPortBaseAddress + I2C_REG_TAR;\r
664           Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
665           Data &= ~B_I2C_REG_TAR;\r
666           Data |= I2CAddress;\r
667           *((volatile uint32_t *) (uintn_t)(Addr)) = Data;\r
668 \r
669           // Enable the I2C Controller\r
670           EnableI2CController ();\r
671 \r
672           // Write the data (sub-addresses) to the IC_DATA_CMD register.\r
673           Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;\r
674           for (Index = 0; Index < WriteLength; Index++)\r
675           {\r
676                   Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
677           Data &= 0xFFFFFF00;\r
678           Data |= (uint8_t)Buffer[Index];\r
679           Data &= ~B_I2C_REG_DATA_CMD_RW;\r
680           *((volatile uint32_t *) (uintn_t)(Addr)) = Data;\r
681           }\r
682 \r
683           // Issue Read Transfers for each byte (Restart issued when write/read bit changed).\r
684           for (Index = 0; Index < ReadLength; Index++)\r
685           {\r
686                   Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
687                   Data |= B_I2C_REG_DATA_CMD_RW;\r
688                   // Issue a STOP for last read transfer.\r
689                   if (Index == (ReadLength-1))\r
690                           Data |= B_I2C_REG_DATA_CMD_STOP;\r
691                   *((volatile uint32_t *) (uintn_t)(Addr)) = Data;\r
692           }\r
693 \r
694           // Wait for STOP condition.\r
695           Status = WaitForStopDet();\r
696           if (Status != 0)\r
697           {\r
698                   // Poll Receive FIFO Buffer Level register until valid (upto MAX_T_POLL_COUNT times).\r
699                   Data = 0;\r
700                   PollCount = 0;\r
701                   Addr = I2CIoPortBaseAddress + I2C_REG_RXFLR;\r
702                   Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
703                   while ((Data != ReadLength) && (PollCount < MAX_T_POLL_COUNT))\r
704                   {\r
705                           vMicroSecondDelay(TI2C_POLL);\r
706                           PollCount++;\r
707                           Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
708                   }\r
709 \r
710                   Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;\r
711                   Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
712 \r
713                   // If no timeout or device error then read rx data.\r
714                   if (PollCount == MAX_T_POLL_COUNT)\r
715                   {\r
716                           Status = -1;\r
717                   }\r
718                   else if ((Data & I2C_REG_RAW_INTR_STAT_RX_OVER) != 0)\r
719                   {\r
720                           Status = -1;\r
721                   }\r
722                   else\r
723                   {\r
724                           // Clear RX underflow before reading IC_DATA_CMD.\r
725                           Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_UNDER;\r
726                           Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
727 \r
728                           // Read data.\r
729                           Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;\r
730                           for (Index = 0; Index < ReadLength; Index++)\r
731                           {\r
732                                   Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
733                                   Data &= 0x000000FF;\r
734                                   *(Buffer+Index) = (uint8_t)Data;\r
735                           }\r
736                           Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;\r
737                           Data = *((volatile uint32_t *) (uintn_t)(Addr));\r
738                           Data &= I2C_REG_RAW_INTR_STAT_RX_UNDER;\r
739                           if (Data != 0)\r
740                           {\r
741                                   Status = -1;\r
742                           }\r
743                           else\r
744                           {\r
745                                   Status = 0;\r
746                           }\r
747                   }\r
748           }\r
749 \r
750           // Ensure I2C Controller disabled.\r
751           DisableI2CController ();\r
752 \r
753           return Status;\r
754   }\r
755   /*-----------------------------------------------------------*/\r
756 \r
757  static void I2CReadMultipleBytes(I2C_DEVICE_ADDRESS SlaveAddress, I2C_ADDR_MODE AddrMode,\r
758  uintn_t *WriteLength, uintn_t *ReadLength, void *Buffer )\r
759  {\r
760           uintn_t  I2CAddress;\r
761           uint16_t SaveCmd;\r
762           uint32_t SaveBar0;\r
763 \r
764           if (Buffer != NULL && WriteLength != NULL && ReadLength != NULL)\r
765           {\r
766                   SaveCmd = 0;\r
767                   SaveBar0 = 0;\r
768                   I2cEntry (&SaveCmd, &SaveBar0);\r
769                   if (InitializeInternal(AddrMode) == 0)\r
770                   {\r
771                           I2CAddress = SlaveAddress.I2CDeviceAddress;\r
772                           ReadMultipleByte(I2CAddress, Buffer, (*WriteLength), (*ReadLength));\r
773                   }\r
774                   I2cExit (SaveCmd, SaveBar0);\r
775           }\r
776  }\r
777  /*-----------------------------------------------------------*/\r
778 \r
779  /*-----------------------------------------------------------------------\r
780   * Pcal9555 chips used on Galileo Gen 2 boards (see FAB-H schematic)\r
781   *------------------------------------------------------------------------\r
782   */\r
783  static void Pcal9555SetPortRegBit(uint32_t Pcal9555SlaveAddr, uint32_t GpioNum, uint8_t RegBase, uint8_t LogicOne)\r
784  {\r
785          uintn_t            ReadLength;\r
786          uintn_t            WriteLength;\r
787          uint8_t            Data[2];\r
788          uint8_t            *RegValuePtr;\r
789          uint8_t            GpioNumMask;\r
790          uint8_t            SubAddr;\r
791          I2C_DEVICE_ADDRESS I2cDeviceAddr;\r
792          I2C_ADDR_MODE      I2cAddrMode;\r
793 \r
794          // Set I2C address and mode.\r
795          I2cDeviceAddr.I2CDeviceAddress = (uintn_t) Pcal9555SlaveAddr;\r
796          I2cAddrMode = EfiI2CSevenBitAddrMode;\r
797 \r
798          // Set I2C subaddress and GPIO mask.\r
799          if (GpioNum < 8)\r
800          {\r
801                  SubAddr = RegBase;\r
802                  GpioNumMask = (uintn_t) (1 << GpioNum);\r
803          }\r
804          else\r
805          {\r
806                  SubAddr = RegBase + 1;\r
807                  GpioNumMask = (uintn_t) (1 << (GpioNum - 8));\r
808          }\r
809 \r
810          // Output port value always at 2nd byte in Data variable.\r
811          RegValuePtr = &Data[1];\r
812 \r
813          // On read entry - sub address at 2nd byte, on read exit - output\r
814          // port value in 2nd byte.\r
815          Data[1] = SubAddr;\r
816          WriteLength = 1;\r
817          ReadLength = 1;\r
818          I2CReadMultipleBytes(I2cDeviceAddr, I2cAddrMode, &WriteLength, &ReadLength,  &Data[1]);\r
819 \r
820          // Adjust output port bit using mask value.\r
821          if (LogicOne)\r
822                  *RegValuePtr = *RegValuePtr | GpioNumMask;\r
823          else\r
824                  *RegValuePtr = *RegValuePtr & ~(GpioNumMask);\r
825 \r
826          // Update register. Sub address at 1st byte, value at 2nd byte.\r
827          WriteLength = 2;\r
828          Data[0] = SubAddr;\r
829          I2CWriteMultipleBytes(I2cDeviceAddr,I2cAddrMode, &WriteLength, Data);\r
830  }\r
831  /*-----------------------------------------------------------*/\r
832 \r
833  static void PlatformPcal9555GpioPullup(uint32_t Pcal9555SlaveAddr, uint32_t GpioNum, uint32_t Enable)\r
834  {\r
835           Pcal9555SetPortRegBit(Pcal9555SlaveAddr, GpioNum, PCAL9555_REG_PULL_EN_PORT0, Enable );\r
836  }\r
837  /*-----------------------------------------------------------*/\r
838 \r
839  static void PlatformPcal9555GpioSetDir(uint32_t Pcal9555SlaveAddr, uint32_t GpioNum, uint32_t CfgAsInput)\r
840  {\r
841           Pcal9555SetPortRegBit(Pcal9555SlaveAddr, GpioNum, PCAL9555_REG_CFG_PORT0, CfgAsInput);\r
842  }\r
843  /*-----------------------------------------------------------*/\r
844 \r
845  static void PlatformPcal9555GpioSetLevel(uint32_t Pcal9555SlaveAddr, uint32_t GpioNum, uint32_t HighLevel )\r
846  {\r
847           Pcal9555SetPortRegBit(Pcal9555SlaveAddr, GpioNum, PCAL9555_REG_OUT_PORT0, HighLevel );\r
848  }\r
849  /*-----------------------------------------------------------*/\r
850 \r
851  /*-----------------------------------------------------------------------\r
852   * GPIO pin routing function\r
853   *------------------------------------------------------------------------\r
854   */\r
855  static void vGalileoRouteLEDPins(void)\r
856  {\r
857          // For GpioNums below values 0 to 7 are for Port0 IE. P0-0 - P0-7 and\r
858          // values 8 to 15 are for Port1 IE. P1-0 - P1-7.\r
859          // Disable Pull-ups / pull downs on EXP0 pin for LVL_B_PU7 signal.\r
860          PlatformPcal9555GpioPullup (\r
861          GALILEO_GEN2_IOEXP0_7BIT_SLAVE_ADDR,  // IO Expander 0.\r
862      15,                                   // P1-7.\r
863      FALSE\r
864      );\r
865 \r
866      // Make LVL_B_OE7_N an output pin.\r
867      PlatformPcal9555GpioSetDir (\r
868      GALILEO_GEN2_IOEXP0_7BIT_SLAVE_ADDR,  // IO Expander 0.\r
869      14,                                   // P1-6.\r
870      FALSE);\r
871 \r
872      // Set level of LVL_B_OE7_N to low.\r
873      PlatformPcal9555GpioSetLevel (\r
874      GALILEO_GEN2_IOEXP0_7BIT_SLAVE_ADDR,\r
875      14,\r
876      FALSE);\r
877 \r
878      // Make MUX8_SEL an output pin.\r
879      PlatformPcal9555GpioSetDir (\r
880      GALILEO_GEN2_IOEXP1_7BIT_SLAVE_ADDR,  // IO Expander 1.\r
881      14,                                   // P1-6.\r
882      FALSE);\r
883 \r
884      // Set level of MUX8_SEL to low to route GPIO_SUS<5> to LED.\r
885      PlatformPcal9555GpioSetLevel (\r
886      GALILEO_GEN2_IOEXP1_7BIT_SLAVE_ADDR,  // IO Expander 1.\r
887      14,                                   // P1-6.\r
888      FALSE);\r
889  }\r
890  /*-----------------------------------------------------------*/\r