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