Setting up repository
[linux-libre-firmware.git] / ath9k_htc / sboot / magpie_1_1 / sboot / cmnos / eeprom / src / cmnos_eeprom.c
1 /*
2  * Copyright (c) 2013 Qualcomm Atheros, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted (subject to the limitations in the
7  * disclaimer below) provided that the following conditions are met:
8  *
9  *  * Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  *  * Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the
15  *    distribution.
16  *
17  *  * Neither the name of Qualcomm Atheros nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific prior written permission.
20  *
21  * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
22  * GRANTED BY THIS LICENSE.  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
23  * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
24  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
32  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
33  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 #include "athos_api.h"
36
37
38 #if SYSTEM_MODULE_EEPROM
39
40 // DEBUG DELAY OF RC ACCESS!!!!!! SHOULD BE FIXED!
41 #define PCIE_RC_ACCESS_DELAY    20
42
43 #define PCI_RC_RESET_BIT                            BIT6
44 #define PCI_RC_PHY_RESET_BIT                        BIT7
45 #define PCI_RC_PLL_RESET_BIT                        BIT8
46 #define PCI_RC_PHY_SHIFT_RESET_BIT                  BIT10
47
48 #define H_EEPROM_CTRL                               0x401c
49     #define B_EEP_CTRL_CLKDIV                       (BIT2|BIT3|BIT4|BIT5|BIT6|BIT7)
50     #define B_EEP_CTRL_NOT_PRESENT                  (BIT8)
51     #define B_EEP_CTRL_CORRUPT                      (BIT9)
52
53 #define H_EEPROM_STS_DATA                           0x407c
54     #define B_EEP_STS_STATE_BUSY                    (BIT16)
55     #define B_EEP_STS_IS_BUSY                       (BIT17)
56     #define B_EEP_STS_PROTECTED                     (BIT18)
57     #define B_EEP_STS_DATA_NOT_EXIST                (BIT19)
58
59 #define CMD_PCI_RC_RESET_ON()    HAL_WORD_REG_WRITE(MAGPIE_REG_RST_RESET_ADDR,  \
60                                     (HAL_WORD_REG_READ(MAGPIE_REG_RST_RESET_ADDR)|  \
61                                         (PCI_RC_PHY_SHIFT_RESET_BIT|PCI_RC_PLL_RESET_BIT|PCI_RC_PHY_RESET_BIT|PCI_RC_RESET_BIT)))
62
63 #define CMD_PCI_RC_RESET_CLR()   HAL_WORD_REG_WRITE(MAGPIE_REG_RST_RESET_ADDR, \
64                                     (HAL_WORD_REG_READ(MAGPIE_REG_RST_RESET_ADDR)&   \
65                                         (~(PCI_RC_PHY_SHIFT_RESET_BIT|PCI_RC_PLL_RESET_BIT|PCI_RC_PHY_RESET_BIT|PCI_RC_RESET_BIT))))
66
67
68 ////////////////////////////////////////////////////////////////////////////////////////////////
69
70
71 /*! eep write half word
72  *
73  * offset: is the offset address you want to do the write operation
74  * data: is the data to write to eeprom
75  *
76  * return: TRUE/FALSE
77  */
78 LOCAL BOOLEAN cmnos_eeprom_write_hword(uint16_t offset, uint16_t data)
79 {
80         /*! - Livy sugguest not use the retry, since it'll be huge retry count
81          *    so that, supposed that if the apb or pcie_rc is working fine,
82          *    we should always could see the NOT_BUSY, otherwise,
83          *        it should have something worng!, put a little delay in there,
84      *
85          *  - debug string here will be noisy!!
86          */
87     //uint16_t retryCnt = 1000;
88
89 #if defined(PROJECT_MAGPIE)
90     //gpio configuration, set GPIOs output to value set in output reg
91     HAL_WORD_REG_WRITE((EEPROM_CTRL_BASE+0x4054), (HAL_WORD_REG_READ((EEPROM_CTRL_BASE+0x4054)) | 0x20000));
92     HAL_WORD_REG_WRITE((EEPROM_CTRL_BASE+0x4060), 0);
93     HAL_WORD_REG_WRITE((EEPROM_CTRL_BASE+0x4064), 0);
94
95     //GPIO3 always drive output
96     HAL_WORD_REG_WRITE((EEPROM_CTRL_BASE+0x404c), 0xc0);
97
98     //Set 0 on GPIO3
99     HAL_WORD_REG_WRITE((EEPROM_CTRL_BASE+0x4048), 0x0);
100 #endif
101
102     HAL_WORD_REG_WRITE(EEPROM_ADDR_BASE + offset*4, (uint32_t)data);
103
104     //while( retryCnt-- > 0 )
105         while(1)
106     {
107         if( (HAL_WORD_REG_READ((EEPROM_CTRL_BASE+H_EEPROM_STS_DATA))&(B_EEP_STS_STATE_BUSY | B_EEP_STS_IS_BUSY)) == 0 )
108         {
109             return(TRUE);
110         }
111 //        A_DELAY_USECS(100);
112     }
113
114     return FALSE;
115 }
116
117 /*! eep read half word
118  *
119  *  offset: is the offset address you want to do the read operation
120  *
121  *  return: the data we read from eeprom
122  */
123 LOCAL BOOLEAN cmnos_eeprom_read_hword(uint16_t offset, uint16_t *mData)
124 {
125     uint32_t mStsData;
126     //uint16_t retryCnt = 1000;
127
128     HAL_WORD_REG_READ(EEPROM_ADDR_BASE + offset*4);
129
130     //while( retryCnt-- > 0 )
131         while(1)
132     {
133         mStsData = HAL_WORD_REG_READ((EEPROM_CTRL_BASE+H_EEPROM_STS_DATA));
134
135         if( (mStsData&(B_EEP_STS_STATE_BUSY | B_EEP_STS_IS_BUSY)) == 0 )
136         {
137             *mData = (uint16_t)(mStsData & 0xffff);
138             return TRUE;
139         }
140 //              A_DELAY_USECS(100);
141     }
142
143     return FALSE;
144 }
145 //////////////////////////////////////////////////////////////////////////////////////////////////////
146
147 LOCAL BOOLEAN eep_state = FALSE;
148 LOCAL BOOLEAN eep_exist = FALSE;
149
150
151 /*!- Initialize eeprom, actually we link up the pcie_rc for accessing the eeprom in client card
152  *
153  */
154 LOCAL T_EEP_RET
155 cmnos_eep_is_exist(void)
156 {
157     if( FALSE != eep_state )
158     {
159         if( FALSE == eep_exist )
160         {
161             uint16_t mData = HAL_WORD_REG_READ((EEPROM_CTRL_BASE+H_EEPROM_CTRL));
162
163             if( mData&B_EEP_CTRL_NOT_PRESENT )
164                 return RET_NOT_EXIST;
165             else if ( mData&B_EEP_CTRL_CORRUPT )
166                 return RET_EEP_CORRUPT;
167             else {
168                 eep_exist = TRUE;
169                 return RET_SUCCESS;
170                 }
171         }
172         else    // already done the checking, fast response
173             return RET_SUCCESS;
174     }
175
176     return RET_NOT_INIT;
177 }
178
179 /*!- eeprom write
180  *
181  * offset: where to write
182  * len:    number of half-word of the pBuf
183  * pBuf:   data buffer to write
184  */
185 LOCAL T_EEP_RET
186 cmnos_eep_write(uint16_t offset, uint16_t len, uint16_t *pBuf)
187 {
188     T_EEP_RET retVal;
189     uint16_t *pData = (uint16_t*)pBuf;
190     uint16_t i, j;
191
192     uint16_t eep_start_ofst = EEPROM_START_OFFSET;
193     uint16_t eep_end_ofst = EEPROM_END_OFFSET;
194     
195
196     if( FALSE != eep_state )
197     {
198                 if( (offset < eep_start_ofst) || (offset > eep_end_ofst) || ((offset+len) > eep_end_ofst) )
199                 {
200                     A_PUTS("-E10-");
201             retVal = RET_EEP_OVERFLOW;
202                 }
203         else
204         {
205             for(i=offset, j=0; i<len+(offset); i++, j++)
206             {
207                 if( TRUE == cmnos_eeprom_write_hword(i, pData[j]) )
208                 {
209                     retVal = RET_SUCCESS;
210                 }
211                 else
212                     A_PUTS("-E11-");
213             }
214         }
215     }
216     else
217     {
218         A_PUTS("-E12-");
219         retVal = RET_NOT_INIT;
220     }
221
222     return retVal;
223 }
224
225 /*!- eeprom read
226  *
227  * offset: where to read
228  * len:    number of bytes to read
229  * pBuf:   data buffer to read
230  */
231 LOCAL T_EEP_RET
232 cmnos_eep_read(uint16_t offset, uint16_t len, uint16_t *pBuf)
233 {
234     T_EEP_RET retVal;
235     uint16_t i;
236     uint16_t *mData = pBuf;
237
238     uint16_t eep_start_ofst = EEPROM_START_OFFSET;
239     uint16_t eep_end_ofst = EEPROM_END_OFFSET;
240
241     if( FALSE != eep_state )
242     {
243                 if( (offset < eep_start_ofst) || (offset > eep_end_ofst) || ((offset+len) > eep_end_ofst) )
244                 {
245                     A_PUTS("-E13-");
246             retVal = RET_EEP_OVERFLOW;
247                 }
248                 else
249                 {
250                     for(i=(offset); i<len+(offset); i++)
251                     {
252                         if( cmnos_eeprom_read_hword(i, mData) )
253                 {
254                     mData++;
255                         }
256                     }
257
258                     retVal = RET_SUCCESS;
259                 }
260     }
261     else
262         retVal = RET_NOT_INIT;
263
264     return retVal;
265
266 }
267
268
269 /*!- Initialize eeprom, actually we link up the pcie_rc for accessing the eeprom in client card
270  *
271  * Ryan - Add setup for PLL, refer to bug#37418
272  *
273  *  5. clear PCIE_RC_PLL PCIE_PHY_SHIFT, PCIE_PHY, PCIE_RC rst bit
274  *  6. clear PCIE_PLL bypass mode and PWD bit (BIT16 and BIT18)
275  *  7. set bus master and memory space enable 
276  *  8. set app_ltssm_enable
277  *
278  *  200ns in each access
279  *
280  */
281 LOCAL void
282 cmnos_eep_init(void)
283 {
284     uint32_t mStsData;
285     volatile int32_t i = 10000;
286     volatile reg_value = 0x0;
287
288 #if defined(PROJECT_MAGPIE)
289     if( TRUE != eep_state )
290     {
291         DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x40;
292
293         /* 5 */
294 #if defined(MAGPIE_FPGA)
295         if (*(volatile uint32_t *)(WATCH_DOG_MAGIC_PATTERN_ADDR) == WDT_MAGIC_PATTERN )
296         {
297         // fpga will hang since external pcie_rc is not able to reset, do a wdt check here, and avoid toching pcie_rc phy reset
298         // not know will real chip have same issue, ryan
299         //
300             DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x41;
301         
302 /*        
303     // Paddu sugguest to remove these, since PCIE_RC's reset state is 1 already
304     //
305             HAL_WORD_REG_WRITE(MAGPIE_REG_RST_RESET_ADDR,  \
306                 (HAL_WORD_REG_READ(MAGPIE_REG_RST_RESET_ADDR)|  \
307                     (PCI_RC_PLL_RESET_BIT|PCI_RC_RESET_BIT)));
308
309             A_DELAY_USECS(PCIE_RC_ACCESS_DELAY);
310             
311             DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x42;
312 */         
313             HAL_WORD_REG_WRITE(MAGPIE_REG_RST_RESET_ADDR, \
314                 (HAL_WORD_REG_READ(MAGPIE_REG_RST_RESET_ADDR)&   \
315                     (~(PCI_RC_PLL_RESET_BIT|PCI_RC_RESET_BIT))));
316
317             A_DELAY_USECS(PCIE_RC_ACCESS_DELAY);
318         }
319         else
320 #endif
321         {
322 /*
323      // Paddu sugguest to remove these, since PCIE_RC's reset state is 1 already
324      // rom1.0 fix: looks like resetting the rc even already in reset state is fine 
325      //             but this would fix the eeprom-less issue, when we do the 2n init
326 */
327             /* asser the reset to pcie_rc */
328             DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x43;
329             CMD_PCI_RC_RESET_ON();
330             A_DELAY_USECS(PCIE_RC_ACCESS_DELAY);
331
332             /* dereset the reset */
333             DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x44;
334             CMD_PCI_RC_RESET_CLR();
335             A_DELAY_USECS(500);
336         }
337
338 /*!
339  * Ryan - clr MAGPIE_REG_AHB_ARB_ADDR, BIT1 is needed no mater FPGA or ASIC
340  */
341 //#if defined(MAGPIE_FPGA)
342     // workaround for FPGA, do we need to enable the PCIE_RC DMA just for accessing the EEPROM?
343     //HAL_WORD_REG_WRITE(0x00050018, 0x6);, purpose is to enable pcie_rc access internal memory
344     //HAL_WORD_REG_WRITE(MAGPIE_REG_AHB_ARB_ADDR, (HAL_WORD_REG_READ(MAGPIE_REG_AHB_ARB_ADDR)|(BIT1|BIT2)));
345         
346         DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x49;
347         HAL_WORD_REG_WRITE(MAGPIE_REG_AHB_ARB_ADDR,
348             (HAL_WORD_REG_READ(MAGPIE_REG_AHB_ARB_ADDR)|(BIT1)));
349         A_DELAY_USECS(PCIE_RC_ACCESS_DELAY);
350 //#endif
351
352         /* 7.5. asser pcie_ep reset */
353         HAL_WORD_REG_WRITE(0x00040018, (HAL_WORD_REG_READ(0x00040018) & ~(0x1 << 2))); 
354
355 #if defined(MAGPIE_ASIC)
356         /* PLL setup should be ASIC/DV specific */
357         /* 6. set PCIE_PLL in bypass mode, and get out of power-down,  */
358         DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x50;
359         HAL_WORD_REG_WRITE(MAGPIE_REG_PCIE_PLL_CONFIG_ADDR, \
360             (HAL_WORD_REG_READ(MAGPIE_REG_PCIE_PLL_CONFIG_ADDR)&(~(BIT16|BIT18))));
361
362         /* 100us delay wait for PCIE PLL stable */
363         A_DELAY_USECS(100); 
364 #endif      
365
366         /* 7. set bus master and memory space enable */
367         DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x45;
368         HAL_WORD_REG_WRITE(0x00020004, (HAL_WORD_REG_READ(0x00020004)|(BIT1|BIT2)));
369         A_DELAY_USECS(PCIE_RC_ACCESS_DELAY);
370
371         /* 7.5. de-asser pcie_ep reset */
372         HAL_WORD_REG_WRITE(0x00040018, (HAL_WORD_REG_READ(0x00040018)|(0x1 << 2)));
373         A_DELAY_USECS(PCIE_RC_ACCESS_DELAY);
374
375         /* 8. set app_ltssm_enable */
376         DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x46;
377         HAL_WORD_REG_WRITE(0x00040000, (HAL_WORD_REG_READ(0x00040000)|0xffc1));
378         
379         /*!
380          * Receive control (PCIE_RESET), 
381          *  0x40018, BIT0: LINK_UP, PHY Link up -PHY Link up/down indicator
382          *  in case the link up is not ready and we access the 0x14000000, 
383          *  vmc will hang here
384          */
385
386         /* poll 0x40018/bit0 (1000 times) until it turns to 1 */
387         while(i-->0)
388         {
389             reg_value = HAL_WORD_REG_READ(0x00040018);
390             if( reg_value & BIT0 ) 
391                 break;
392             A_DELAY_USECS(PCIE_RC_ACCESS_DELAY); 
393         }
394
395         /* init fail, can't detect PCI_RC LINK UP, give up the init */
396         if( i<=0 )
397         {
398                         DEBUG_SYSTEM_STATE |= BIT26;
399             goto ERR_DONE;
400         }
401
402         DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x47;
403         HAL_WORD_REG_WRITE(0x14000004, (HAL_WORD_REG_READ(0x14000004)|0x116));
404         A_DELAY_USECS(PCIE_RC_ACCESS_DELAY);
405
406         DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x48;
407         HAL_WORD_REG_WRITE(0x14000010, (HAL_WORD_REG_READ(0x14000010)|EEPROM_CTRL_BASE));
408         eep_state = TRUE;
409     }
410
411 #elif defined(PROJECT_K2)
412     eep_state = TRUE;
413 #endif /* End of #if defined(PROJECT_MAGPIE) */
414     if (TRUE == eep_state)
415     {
416         /* Read offset 1 location to determine if this EEPROM is protected somewhere */
417         HAL_WORD_REG_READ(EEPROM_ADDR_BASE + 4);
418
419         while(1)
420         {
421             mStsData = HAL_WORD_REG_READ((EEPROM_CTRL_BASE+H_EEPROM_STS_DATA));
422
423             /* If this location is protected or EEPROM does not exist, return immediately */
424             if ( mStsData & (B_EEP_STS_PROTECTED | B_EEP_STS_DATA_NOT_EXIST) )
425             {
426                 eep_state = FALSE;
427                 break;
428             }
429
430             if ( ( mStsData & (B_EEP_STS_STATE_BUSY | B_EEP_STS_IS_BUSY) ) == 0 )
431             {
432                 if (mStsData & 0xffff)
433                     cmnos_eeprom_write_hword( (uint16_t)1, (uint16_t)0 );
434
435                 break;
436             }
437
438                 A_DELAY_USECS(100);
439         }
440     }
441 ERR_DONE:
442     
443 }
444
445
446 void
447 cmnos_eep_module_install(struct eep_api *tbl)
448 {
449     tbl->_eep_init          = cmnos_eep_init;
450     tbl->_eep_read          = cmnos_eep_read;
451     tbl->_eep_write         = cmnos_eep_write;
452     tbl->_eep_is_exist      = cmnos_eep_is_exist;
453 }
454
455 #endif /* SYSTEM_MODULE_EEPROM */
456