1  /******************************************************************************
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  *
21  * Copyright 2014 QLogic Corporation
22  * The contents of this file are subject to the terms of the
23  * QLogic End User License (the "License").
24  * You may not use this file except in compliance with the License.
25  *
26  * You can obtain a copy of the License at
27  * http://www.qlogic.com/Resources/Documents/DriverDownloadHelp/
28  * QLogic_End_User_Software_License.txt
29  * See the License for the specific language governing permissions
30  * and limitations under the License.
31  *
32  *
33  * Module Description:
34  *
35  *
36  * History:
37  *    03/21/03 Hav Khauv        Inception.
38  ******************************************************************************/
39 
40 #include "lm5710.h"
41 
42 #define NVRAM_TIMEOUT_COUNT                     100000
43 
44 
45 /*******************************************************************************
46  * Description:
47  *
48  * Return:
49  ******************************************************************************/
50 static lm_status_t
acquire_nvram_lock(lm_device_t * pdev)51 acquire_nvram_lock(
52     lm_device_t *pdev)
53 {
54     lm_status_t lm_status;
55     u32_t j, cnt;
56     u32_t val;
57     u8_t port_num = PORT_ID(pdev); /* TBD - E1H: nvram lock � DOES NOT scale to 8 functions! (only 4 clients)
58                                     * 1. Can we assume no concurrent access by control applications?
59                                     * 2. If not, the MISC lock is our backup */
60 
61     DbgMessage(pdev, VERBOSEnv, "### acquire_nvram_lock\n");
62     /* Adjust timeout for emulation/FPGA */
63     cnt = NVRAM_TIMEOUT_COUNT;
64     if (CHIP_REV_IS_EMUL(pdev)) cnt *= 100;
65 
66     val = 0;
67 
68     /* Request access to the flash interface. */
69     REG_WR(pdev, MCP_REG_MCPR_NVM_SW_ARB, (MCPR_NVM_SW_ARB_ARB_REQ_SET1 << port_num ));
70     for(j = 0; j < cnt*10; j++)
71     {
72         val=REG_RD(pdev, MCP_REG_MCPR_NVM_SW_ARB);
73         if(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port_num))
74         {
75             break;
76         }
77 
78         mm_wait(pdev, 5);
79     }
80 
81     if(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port_num))
82     {
83         lm_status = LM_STATUS_SUCCESS;
84     }
85     else
86     {
87         DbgMessage(NULL, FATAL, "Value of MCP_REG_MCPR_NVM_SW_ARB is 0x%x\n", val);
88         DbgBreakMsg("Cannot get access to nvram interface.\n");
89 
90         lm_status = LM_STATUS_BUSY;
91     }
92 
93     return lm_status;
94 } /* acquire_nvram_lock */
95 
96 
97 
98 /*******************************************************************************
99  * Description:
100  *
101  * Return:
102  ******************************************************************************/
103 static void
release_nvram_lock(lm_device_t * pdev)104 release_nvram_lock(
105     lm_device_t *pdev)
106 {
107     u32_t j, cnt;
108     u32_t val;
109     u8_t port_num = PORT_ID(pdev);
110 
111     DbgMessage(pdev, VERBOSEnv, "### release_nvram_lock\n");
112     /* Adjust timeout for emulation/FPGA */
113     cnt = NVRAM_TIMEOUT_COUNT;
114     if (CHIP_REV_IS_EMUL(pdev)) cnt *= 100;
115 
116     /* Relinquish nvram interface. */
117     REG_WR(pdev,  MCP_REG_MCPR_NVM_SW_ARB, (MCPR_NVM_SW_ARB_ARB_REQ_CLR1 << port_num));
118 
119     val = 0;
120 
121     for(j = 0; j < cnt; j++)
122     {
123         val=REG_RD(pdev, MCP_REG_MCPR_NVM_SW_ARB);
124         if(!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port_num)))
125         {
126             break;
127         }
128 
129         mm_wait(pdev, 5);
130     }
131 
132     DbgBreakIf(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port_num));
133 } /* release_nvram_lock */
134 
135 
136 #if 0
137 /*******************************************************************************
138 * Description:
139 *
140 * Return:
141 *
142 ******************************************************************************/
143 static lm_status_t
144 enable_nvram_write(
145    lm_device_t *pdev)
146 {
147     u32_t val, j, cnt;
148     lm_status_t lm_status;
149 
150     lm_status = LM_STATUS_SUCCESS;
151 
152     DbgMessage(pdev, INFORMnv, "### enable_nvram_write\n");
153 
154     /* Need to clear DONE bit separately. */
155     REG_WR(pdev, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE);
156 
157     /* Issue a write enable command. */
158     REG_WR(pdev, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DOIT | MCPR_NVM_COMMAND_WREN);
159 
160     /* Adjust timeout for emulation/FPGA */
161     cnt = NVRAM_TIMEOUT_COUNT;
162     if (CHIP_REV(pdev) == CHIP_REV_EMUL) cnt *= 100;
163 
164     lm_status = LM_STATUS_BUSY;
165 
166     for(j = 0; j < cnt; j++)
167     {
168         mm_wait(pdev, 5);
169 
170         val=REG_RD(pdev,  MCP_REG_MCPR_NVM_COMMAND);
171         if(val & MCPR_NVM_COMMAND_DONE)
172         {
173             lm_status = LM_STATUS_SUCCESS;
174             break;
175         }
176     }
177 
178     return lm_status;
179 } /* enable_nvram_write */
180 
181 
182 
183 /*******************************************************************************
184 * Description:
185 *
186 * Return:
187 *
188 ******************************************************************************/
189 static lm_status_t
190 disable_nvram_write(
191                     lm_device_t *pdev)
192 {
193     lm_status_t lm_status;
194     u32_t cnt,j,val;
195 
196     DbgMessage(pdev, INFORMnv, "### disable_nvram_write\n");
197     /* Need to clear DONE bit separately. */
198     REG_WR(pdev, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE);
199 
200         /* Issue a write disable command. */
201     REG_WR(pdev, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DOIT | MCPR_NVM_COMMAND_WRDI);
202 
203     /* Adjust timeout for emulation/FPGA */
204     cnt = NVRAM_TIMEOUT_COUNT;
205     if (CHIP_REV(pdev) == CHIP_REV_EMUL) cnt *= 100;
206 
207     lm_status = LM_STATUS_BUSY;
208     for(j = 0; j < cnt; j++)
209     {
210         mm_wait(pdev, 5);
211 
212         val=REG_RD(pdev,  MCP_REG_MCPR_NVM_COMMAND);
213         if(val & MCPR_NVM_COMMAND_DONE)
214         {
215             lm_status = LM_STATUS_SUCCESS;
216             break;
217         }
218     }
219 
220     return lm_status;
221 } /* disable_nvram_write */
222 
223 #endif /* 0 */
224 
225 /*******************************************************************************
226 * Description:
227 *
228 * Return:
229 ******************************************************************************/
230 static lm_status_t
enable_nvram_access(lm_device_t * pdev)231 enable_nvram_access(
232     lm_device_t *pdev)
233 {
234     u32_t val;
235 
236     DbgMessage(pdev, VERBOSEnv, "### enable_nvram_access\n");
237     val=REG_RD(pdev,  MCP_REG_MCPR_NVM_ACCESS_ENABLE);
238 
239     /* Enable both bits, even on read. */
240     REG_WR(pdev,  MCP_REG_MCPR_NVM_ACCESS_ENABLE, val | MCPR_NVM_ACCESS_ENABLE_EN | MCPR_NVM_ACCESS_ENABLE_WR_EN);
241 
242     return LM_STATUS_SUCCESS;
243 } /* enable_nvram_access */
244 
245 
246 
247 /*******************************************************************************
248 * Description:
249 *
250 * Return:
251 ******************************************************************************/
252 static lm_status_t
disable_nvram_access(lm_device_t * pdev)253 disable_nvram_access(
254     lm_device_t *pdev)
255 {
256     u32_t val;
257 
258     DbgMessage(pdev, VERBOSEnv, "### disable_nvram_access\n");
259     val=REG_RD(pdev,  MCP_REG_MCPR_NVM_ACCESS_ENABLE);
260 
261     /* Disable both bits, even after read. */
262     REG_WR(pdev,  MCP_REG_MCPR_NVM_ACCESS_ENABLE, val & ~(MCPR_NVM_ACCESS_ENABLE_EN | MCPR_NVM_ACCESS_ENABLE_WR_EN));
263 
264     return LM_STATUS_SUCCESS;
265 } /* disable_nvram_access */
266 
267 
268 
269 
270 /*******************************************************************************
271  * Description:
272  *
273  * Return:
274  ******************************************************************************/
275 static lm_status_t
nvram_read_dword(lm_device_t * pdev,u32_t offset,u32_t * ret_val,u32_t nvram_flags)276 nvram_read_dword(
277     lm_device_t *pdev,
278     u32_t offset,
279     u32_t *ret_val,
280     u32_t nvram_flags)
281 {
282     lm_status_t lm_status;
283     u32_t cmd_flags;
284     u32_t val;
285     u32_t j, cnt;
286 
287     DbgMessage(pdev, VERBOSEnv, "### nvram_read_dword\n");
288     DbgMessage(pdev, VERBOSEnv, "offset %d flags %d\n",offset,nvram_flags);
289 
290     /* Build the command word. */
291     cmd_flags = nvram_flags | MCPR_NVM_COMMAND_DOIT;
292 
293     /* Need to clear DONE bit separately. */
294     REG_WR(pdev,  MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE);
295 
296     /* Address of the NVRAM to read from. */
297     REG_WR(pdev,  MCP_REG_MCPR_NVM_ADDR, offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE);
298 
299     /* Issue a read command. */
300     REG_WR(pdev,  MCP_REG_MCPR_NVM_COMMAND, cmd_flags);
301 
302     /* Adjust timeout for emulation/FPGA */
303     cnt = NVRAM_TIMEOUT_COUNT;
304     if (CHIP_REV_IS_EMUL(pdev)) cnt *= 100;
305 
306     /* Wait for completion. */
307     lm_status = LM_STATUS_BUSY;
308     for(j = 0; j < cnt; j++)
309     {
310         mm_wait(pdev, 5);
311         val=REG_RD(pdev,  MCP_REG_MCPR_NVM_COMMAND);
312         if(val & MCPR_NVM_COMMAND_DONE)
313         {
314             val=REG_RD(pdev,  MCP_REG_MCPR_NVM_READ);
315 
316             /* Change to little endian. */
317             #if defined(LITTLE_ENDIAN)
318             val = ((val & 0xff) << 24) | ((val & 0xff00) << 8) |
319                 ((val & 0xff0000) >> 8) | ((val >> 24) & 0xff);
320             #endif
321 
322             *ret_val = val;
323 
324             lm_status = LM_STATUS_SUCCESS;
325 
326             break;
327         }
328     }
329 
330     return lm_status;
331 } /* nvram_read_dword */
332 
333 
334 
335 /*******************************************************************************
336  * Description:
337  *
338  * Return:
339  ******************************************************************************/
340 static lm_status_t
nvram_write_dword(lm_device_t * pdev,u32_t offset,u32_t val,u32_t nvram_flags)341 nvram_write_dword(
342     lm_device_t *pdev,
343     u32_t offset,
344     u32_t val,
345     u32_t nvram_flags)
346 {
347     lm_status_t lm_status;
348     u32_t cmd_flags;
349     u32_t j, cnt;
350 
351     DbgMessage(pdev, VERBOSEnv, "### nvram_write_dword\n");
352     /* Build the command word. */
353     cmd_flags = nvram_flags | MCPR_NVM_COMMAND_DOIT | MCPR_NVM_COMMAND_WR;
354 
355     /* Change to little endian. */
356     #if defined(LITTLE_ENDIAN)
357     val = ((val & 0xff) << 24) | ((val & 0xff00) << 8) |
358         ((val & 0xff0000) >> 8) | ((val >> 24) & 0xff);
359     #endif
360 
361     /* Need to clear DONE bit separately. */
362     REG_WR(pdev,  MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE);
363 
364     /* Write the data. */
365     REG_WR(pdev,  MCP_REG_MCPR_NVM_WRITE, val);
366 
367     /* Address of the NVRAM to write to. */
368     REG_WR(pdev,  MCP_REG_MCPR_NVM_ADDR, offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE);
369 
370     /* Issue the write command. */
371     REG_WR(pdev,  MCP_REG_MCPR_NVM_COMMAND, cmd_flags);
372 
373     /* Adjust timeout for emulation/FPGA */
374 
375     cnt = NVRAM_TIMEOUT_COUNT;
376     if (CHIP_REV_IS_EMUL(pdev)) cnt *= 100;
377 
378     /* Wait for completion. */
379     lm_status = LM_STATUS_BUSY;
380     for(j = 0; j < cnt; j++)
381     {
382         mm_wait(pdev, 5);
383 
384         val=REG_RD(pdev,  MCP_REG_MCPR_NVM_COMMAND);
385         if(val & MCPR_NVM_COMMAND_DONE)
386         {
387             lm_status = LM_STATUS_SUCCESS;
388             break;
389         }
390     }
391 
392     return lm_status;
393 } /* nvram_write_dword */
394 
395 
396 
397 /*******************************************************************************
398  * Description:
399  *
400  * Return:
401  ******************************************************************************/
402 lm_status_t
lm_nvram_read(lm_device_t * pdev,u32_t offset,u32_t * ret_buf,u32_t buf_size)403 lm_nvram_read(
404     lm_device_t *pdev,
405     u32_t offset,
406     u32_t *ret_buf,
407     u32_t buf_size)
408 {
409     lm_status_t lm_status;
410     u32_t cmd_flags;
411 
412 
413     DbgMessage(pdev, VERBOSEnv, "### lm_nvram_read\n");
414     DbgMessage(pdev, VERBOSEnv, "offset %d size %d\n",offset,buf_size);
415 
416     if((buf_size & 0x03) || (offset & 0x03))
417     {
418         DbgBreakMsg("Invalid paramter.\n");
419 
420         return LM_STATUS_FAILURE;
421     }
422 
423     // TODO what is the nvram total size
424     if(offset + buf_size > pdev->hw_info.flash_spec.total_size)
425     {
426         DbgBreakMsg("Invalid paramter.\n");
427 
428         return LM_STATUS_FAILURE;
429     }
430 
431     /* Request access to the flash interface. */
432     lm_status = acquire_nvram_lock(pdev);
433     if(lm_status != LM_STATUS_SUCCESS)
434     {
435         return lm_status;
436     }
437 
438     /* Enable access to flash interface */
439     lm_status = enable_nvram_access(pdev);
440     if(lm_status != LM_STATUS_SUCCESS)
441     {
442         release_nvram_lock(pdev);
443         return lm_status;
444     }
445 
446     /* Read the first word. */
447     cmd_flags = MCPR_NVM_COMMAND_FIRST;
448     while(buf_size > sizeof(u32_t) && lm_status == LM_STATUS_SUCCESS)
449     {
450         lm_status = nvram_read_dword(pdev, offset, ret_buf, cmd_flags);
451 
452         /* Advance to the next dword. */
453         offset += sizeof(u32_t);
454         ret_buf++;
455         buf_size -= sizeof(u32_t);
456         cmd_flags = 0;
457     }
458 
459     if(lm_status == LM_STATUS_SUCCESS)
460     {
461         cmd_flags |= MCPR_NVM_COMMAND_LAST;
462         lm_status = nvram_read_dword(pdev, offset, ret_buf, cmd_flags);
463     }
464 
465     /* Disable access to flash interface */
466     disable_nvram_access(pdev);
467 
468     release_nvram_lock(pdev);
469 
470     return lm_status;
471 } /* lm_nvram_read */
472 
473 
474 /*******************************************************************************
475  * Description:
476  *
477  * Return:
478  ******************************************************************************/
479 lm_status_t
lm_nvram_write(lm_device_t * pdev,u32_t offset,u32_t * data_buf,u32_t buf_size)480 lm_nvram_write(
481     lm_device_t *pdev,
482     u32_t offset,
483     u32_t *data_buf,
484     u32_t buf_size)
485 {
486     lm_status_t lm_status;
487     u32_t written_so_far;
488     u32_t cmd_flags;
489     u32_t *ptr32, addr;
490 
491     DbgMessage(pdev, VERBOSEnv, "### lm_nvram_write\n");
492 
493     if(offset & 0x03)
494     {
495         DbgBreakMsg("Invalid paramter.\n");
496 
497         return LM_STATUS_FAILURE;
498     }
499     // TODO what is the nvram total size
500     if(offset + buf_size > pdev->hw_info.flash_spec.total_size)
501     {
502 	DbgMessage(pdev, FATAL, "lm_nvram_write failed ! buf_size %d larger than NVM total_size %d\n", buf_size, pdev->hw_info.flash_spec.total_size);
503         DbgBreakMsg("Failed to write to NVM! Attemp to write to offset larger than NVM total size !\n");
504 
505         return LM_STATUS_FAILURE;
506     }
507 
508     lm_status = LM_STATUS_SUCCESS;
509 
510     /* Request access to the flash interface. */
511     lm_status = acquire_nvram_lock(pdev);
512     if(lm_status != LM_STATUS_SUCCESS)
513         return lm_status;
514 
515     /* Enable access to flash interface */
516     lm_status = enable_nvram_access(pdev);
517     if(lm_status != LM_STATUS_SUCCESS)
518     {
519         release_nvram_lock(pdev);
520         return lm_status;
521     }
522 
523     written_so_far = 0;
524     cmd_flags = MCPR_NVM_COMMAND_FIRST;
525     addr = offset;
526     ptr32 = data_buf;
527     while (written_so_far < buf_size)
528     {
529         if (written_so_far == (buf_size - 4))
530             cmd_flags |= MCPR_NVM_COMMAND_LAST;
531         else if (((addr & 0xff) + 4) == NVRAM_PAGE_SIZE)        // else if (((addr + 4) % NVRAM_PAGE_SIZE) == 0)
532             cmd_flags |= MCPR_NVM_COMMAND_LAST;
533         else if ((addr & 0xff) == 0)                            // else if ((addr % NVRAM_PAGE_SIZE) == 0)
534             cmd_flags |= MCPR_NVM_COMMAND_FIRST;
535         nvram_write_dword(pdev, addr, *ptr32, cmd_flags);
536         ptr32++;
537         addr += 4;
538         written_so_far += 4;
539         cmd_flags = 0;
540     }
541     /* Disable access to flash interface */
542     disable_nvram_access(pdev);
543     release_nvram_lock(pdev);
544 
545 
546     return lm_status;
547 
548 } /* lm_nvram_write */
549