1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * Generic NVRAM Driver for STM48Txx chips and the equivalent. 5 * 6 * This module contains a CFE driver for a battery backed SRAM 7 * (Non-volatile) ram region at a configurable base address and 8 * provided size. 9 * 10 * Author: James Dougherty 11 * Mitch Lichtenberg 12 * 13 ********************************************************************* 14 * 15 * Copyright 2000,2001,2002 16 * Broadcom Corporation. All rights reserved. 17 * 18 * This software is furnished under license and may be used and 19 * copied only in accordance with the following terms and 20 * conditions. Subject to these conditions, you may download, 21 * copy, install, use, modify and distribute modified or unmodified 22 * copies of this software in source and/or binary form. No title 23 * or ownership is transferred hereby. 24 * 25 * 1) Any source code used, modified or distributed must reproduce 26 * and retain this copyright notice and list of conditions 27 * as they appear in the source file. 28 * 29 * 2) No right is granted to use any trade name, trademark, or 30 * logo of Broadcom Corporation. The "Broadcom Corporation" 31 * name may not be used to endorse or promote products derived 32 * from this software without the prior written permission of 33 * Broadcom Corporation. 34 * 35 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 36 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 37 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 38 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 39 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 40 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 41 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 42 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 43 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 44 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 45 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 46 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 47 * THE POSSIBILITY OF SUCH DAMAGE. 48 ********************************************************************* */ 49 50#include "cfe.h" 51 52#include "lib_physio.h" 53 54 55/* ********************************************************************* 56 * Constants 57 ********************************************************************* */ 58 59#define M48TXX_NVRAM_SIZE 0x1FF0 60 61#define M48TXX_FLAGS 0x1FF0 62#define M48TXX_CONTROL 0x1FF8 63#define M48TXX_SECOND 0x1FF9 64#define M48TXX_MINUTE 0x1FFA 65#define M48TXX_HOUR 0x1FFB 66#define M48TXX_DAY 0x1FFC 67#define M48TXX_DATE 0x1FFD 68#define M48TXX_MONTH 0x1FFE 69#define M48TXX_YEAR 0x1FFF 70 71#define M_M48TXX_MONTH 0x1F 72#define M_M48TXX_DATE 0x3F 73#define M_M48TXX_DAY 0x07 74#define M_M48TXX_MINUTE 0x7F 75#define M_M48TXX_SECOND 0x7F 76 77/* FLAGS */ 78#define M_M48TXX_BL 0x10 79 80/* CONTROL */ 81#define M_M48TXX_W 0x80 82#define M_M48TXX_R 0x40 83#define M_M48TXX_S 0x20 84 85/* DAY */ 86#define M_M48TXX_FT 0x40 87#define M_M48TXX_CEB 0x20 88#define M_M48TXX_CB 0x10 89 90#define BCD(x) (((x) % 10) + (((x) / 10) << 4)) 91#define SET_TIME 0x00 92#define SET_DATE 0x01 93 94#if ENDIAN_BIG 95#define WRITECSR(p,v) phys_write8((p)^0x3,(v)) 96#define READCSR(p) phys_read8((p)^0x3) 97#else 98#define WRITECSR(p,v) phys_write8((p),(v)) 99#define READCSR(p) phys_read8((p)) 100#endif 101 102/* ********************************************************************* 103 * Forward declarations 104 ********************************************************************* */ 105 106static void m48txx_clock_probe(cfe_driver_t *drv, 107 unsigned long probe_a, unsigned long probe_b, 108 void *probe_ptr); 109 110static int m48txx_clock_open(cfe_devctx_t *ctx); 111static int m48txx_clock_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 112static int m48txx_clock_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); 113static int m48txx_clock_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 114static int m48txx_clock_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 115static int m48txx_clock_close(cfe_devctx_t *ctx); 116 117 118/* ********************************************************************* 119 * Device dispatch 120 ********************************************************************* */ 121 122const static cfe_devdisp_t m48txx_clock_dispatch = { 123 m48txx_clock_open, 124 m48txx_clock_read, 125 m48txx_clock_inpstat, 126 m48txx_clock_write, 127 m48txx_clock_ioctl, 128 m48txx_clock_close, 129 NULL, 130 NULL 131}; 132 133const cfe_driver_t m48txx_clock = { 134 "ST M48Txx RTC", 135 "clock", 136 CFE_DEV_CLOCK, 137 &m48txx_clock_dispatch, 138 m48txx_clock_probe 139}; 140 141 142/* ********************************************************************* 143 * Structures 144 ********************************************************************* */ 145typedef struct m48txx_clock_s { 146 physaddr_t clock_base; 147} m48txx_clock_t; 148 149/* ********************************************************************* 150 * m48txx_clock_probe(drv,a,b,ptr) 151 * 152 * Probe routine for this driver. This routine creates the 153 * local device context and attaches it to the driver list 154 * within CFE. 155 * 156 * Input parameters: 157 * drv - driver handle 158 * a,b - probe hints (longs) 159 * ptr - probe hint (pointer) 160 * 161 * Return value: 162 * nothing 163 ********************************************************************* */ 164 165static void m48txx_clock_probe(cfe_driver_t *drv, 166 unsigned long probe_a, unsigned long probe_b, 167 void *probe_ptr) 168{ 169 m48txx_clock_t *softc; 170 char descr[80]; 171 172 softc = (m48txx_clock_t *) KMALLOC(sizeof(m48txx_clock_t),0); 173 174 /* 175 * Probe_a is the clock base address 176 * Probe_b is unused. 177 * Probe_ptr is unused. 178 */ 179 180 softc->clock_base = probe_a; 181 182 xsprintf(descr,"%s at 0x%X", 183 drv->drv_description,(uint32_t)probe_a); 184 cfe_attach(drv,softc,NULL,descr); 185 186} 187 188/* ********************************************************************* 189 * m48txx_clock_open(ctx) 190 * 191 * Open this device. For the M48TXX, we do a quick test 192 * read to be sure the device is out there. 193 * 194 * Input parameters: 195 * ctx - device context (can obtain our softc here) 196 * 197 * Return value: 198 * 0 if ok 199 * else error code 200 ********************************************************************* */ 201 202static int m48txx_clock_open(cfe_devctx_t *ctx) 203{ 204 m48txx_clock_t *softc = ctx->dev_softc; 205 physaddr_t clockbase; 206 207 clockbase = softc->clock_base; 208 209 /* Make sure battery is still good and RTC valid. */ 210 if ((READCSR(clockbase+M48TXX_FLAGS) & M_M48TXX_BL) != 0) { 211 printf("Warning: Battery has failed. Clock setting is not accurate.\n"); 212 } 213 214 return 0; 215} 216 217/* ********************************************************************* 218 * m48txx_clock_read(ctx,buffer) 219 * 220 * Read time/date from the RTC. Read a total of 8 bytes in this format: 221 * hour-minute-second-month-day-year1-year2 222 * 223 * Input parameters: 224 * ctx - device context (can obtain our softc here) 225 * buffer - buffer descriptor (target buffer, length, offset) 226 * 227 * Return value: 228 * number of bytes read 229 * -1 if an error occured 230 ********************************************************************* */ 231 232static int m48txx_clock_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 233{ 234 235 m48txx_clock_t *softc = ctx->dev_softc; 236 hsaddr_t bptr; 237 physaddr_t clockbase; 238 uint8_t byte; 239 240 clockbase = softc->clock_base; 241 242 bptr = buffer->buf_ptr; 243 244 byte = (uint8_t) (READCSR(clockbase+M48TXX_CONTROL) & 0xFF); 245 WRITECSR(clockbase+M48TXX_CONTROL,M_M48TXX_R | byte); 246 247 248 byte = READCSR(clockbase+M48TXX_HOUR); 249 hs_write8(bptr,byte); bptr++; 250 byte = READCSR(clockbase+M48TXX_MINUTE); 251 hs_write8(bptr,byte); bptr++; 252 byte = READCSR(clockbase+M48TXX_SECOND); 253 hs_write8(bptr,byte); bptr++; 254 byte = READCSR(clockbase+M48TXX_MONTH) & M_M48TXX_MONTH; 255 hs_write8(bptr,byte); bptr++; 256 byte = READCSR(clockbase+M48TXX_DATE) & M_M48TXX_DATE; 257 hs_write8(bptr,byte); bptr++; 258 byte = READCSR(clockbase+M48TXX_YEAR); 259 hs_write8(bptr,byte); bptr++; 260 261 /* Assume that a century bit is present and is set for 20xx. */ 262 byte = READCSR(clockbase+M48TXX_DAY); 263 byte = (byte & M_M48TXX_CB) ? 0x20 : 0x19; 264 hs_write8(bptr,byte); 265 266 byte = (uint8_t) (READCSR(clockbase+M48TXX_CONTROL) & 0xFF); 267 WRITECSR(clockbase+M48TXX_CONTROL,~M_M48TXX_R & byte); 268 269 buffer->buf_retlen = 8; 270 return 0; 271} 272 273/* ********************************************************************* 274 * m48txx_clock_write(ctx,buffer) 275 * 276 * Write time/date to the RTC. Write in this format: 277 * hour-minute-second-month-day-year1-year2-(time/date flag) 278 * 279 * Input parameters: 280 * ctx - device context (can obtain our softc here) 281 * buffer - buffer descriptor (target buffer, length, offset) 282 * 283 * Return value: 284 * number of bytes written 285 * -1 if an error occured 286 ********************************************************************* */ 287 288static int m48txx_clock_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 289{ 290 m48txx_clock_t *softc = ctx->dev_softc; 291 uint8_t byte; 292 hsaddr_t bptr; 293 uint8_t hr,min,sec; 294 uint8_t mo,day,yr,y2k; 295 uint8_t timeDateFlag; 296 physaddr_t clockbase; 297 298 clockbase = softc->clock_base; 299 300 bptr = buffer->buf_ptr; 301 302 /* Set SET bit */ 303 byte = (uint8_t) (READCSR(clockbase+M48TXX_CONTROL) & 0xFF); 304 WRITECSR(clockbase+M48TXX_CONTROL,M_M48TXX_W | byte); 305 306 timeDateFlag = hs_read8(bptr + 7); 307 308 /* write time or date */ 309 if(timeDateFlag == SET_TIME) { 310 311 hr = hs_read8(bptr); 312 WRITECSR(clockbase+M48TXX_HOUR,BCD(hr)); 313 314 min = hs_read8(bptr+1); 315 WRITECSR(clockbase+M48TXX_MINUTE,BCD(min)); 316 317 sec = hs_read8(bptr+2); 318 WRITECSR(clockbase+M48TXX_SECOND,BCD(sec)); 319 320 buffer->buf_retlen = 3; 321 } 322 else if(timeDateFlag == SET_DATE) { 323 324 mo = hs_read8(bptr+3); 325 WRITECSR(clockbase+M48TXX_MONTH,BCD(mo)); 326 327 day = hs_read8(bptr+4); 328 WRITECSR(clockbase+M48TXX_DATE,BCD(day)); 329 330 yr = hs_read8(bptr+5); 331 WRITECSR(clockbase+M48TXX_YEAR,BCD(yr)); 332 333 y2k = hs_read8(bptr+6); 334 byte = READCSR(clockbase+M48TXX_DAY); 335 if (((y2k - 0x19) & 0x1) == 0) 336 byte &= ~M_M48TXX_CB; 337 else 338 byte |= M_M48TXX_CB; 339 byte |= M_M48TXX_CEB; 340 WRITECSR(clockbase+M48TXX_DAY,byte); 341 342 buffer->buf_retlen = 4; 343 } 344 else { 345 return -1; 346 } 347 348 /* clear SET bit */ 349 byte = (uint8_t) (READCSR(clockbase+M48TXX_CONTROL) & 0xFF); 350 WRITECSR(clockbase+M48TXX_CONTROL,~M_M48TXX_W & byte); 351 352 return 0; 353} 354 355/* ********************************************************************* 356 * m48txx_clock_inpstat(ctx,inpstat) 357 * 358 * Test input (read) status for the device 359 * 360 * Input parameters: 361 * ctx - device context (can obtain our softc here) 362 * inpstat - input status descriptor to receive value 363 * 364 * Return value: 365 * 0 if ok 366 * -1 if an error occured 367 ********************************************************************* */ 368 369static int m48txx_clock_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat) 370{ 371 inpstat->inp_status = 1; 372 373 return 0; 374} 375 376/* ********************************************************************* 377 * m48txx_clock_ioctl(ctx,buffer) 378 * 379 * Perform miscellaneous I/O control operations on the device. 380 * 381 * Input parameters: 382 * ctx - device context (can obtain our softc here) 383 * buffer - buffer descriptor (target buffer, length, offset) 384 * 385 * Return value: 386 * number of bytes read 387 * -1 if an error occured 388 ********************************************************************* */ 389 390static int m48txx_clock_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 391{ 392 return 0; 393} 394 395/* ********************************************************************* 396 * m48txx_clock_close(ctx,buffer) 397 * 398 * Close the device. 399 * 400 * Input parameters: 401 * ctx - device context (can obtain our softc here) 402 * 403 * Return value: 404 * 0 if ok 405 * -1 if an error occured 406 ********************************************************************* */ 407 408static int m48txx_clock_close(cfe_devctx_t *ctx) 409{ 410 return 0; 411} 412 413 414/* ********************************************************************* 415 * Forward Declarations 416 ********************************************************************* */ 417 418static void m48txx_nvram_probe(cfe_driver_t *drv, 419 unsigned long probe_a, unsigned long probe_b, 420 void *probe_ptr); 421 422 423static int m48txx_nvram_open(cfe_devctx_t *ctx); 424static int m48txx_nvram_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 425static int m48txx_nvram_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); 426static int m48txx_nvram_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 427static int m48txx_nvram_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 428static int m48txx_nvram_close(cfe_devctx_t *ctx); 429 430/* ********************************************************************* 431 * Dispatch tables 432 ********************************************************************* */ 433 434const static cfe_devdisp_t m48txx_nvram_dispatch = { 435 m48txx_nvram_open, 436 m48txx_nvram_read, 437 m48txx_nvram_inpstat, 438 m48txx_nvram_write, 439 m48txx_nvram_ioctl, 440 m48txx_nvram_close, 441 NULL, 442 NULL 443}; 444 445const cfe_driver_t m48txx_nvram = { 446 "ST M48Txx NVRAM", 447 "nvram", 448 CFE_DEV_NVRAM, 449 &m48txx_nvram_dispatch, 450 m48txx_nvram_probe 451}; 452 453typedef struct m48txx_nvram_s { 454 int base_addr; 455 int dev_size; 456 int env_offset; 457 int env_size; 458 volatile unsigned char* data; /* NV region */ 459} m48txx_nvram_t; 460 461 462 463/* ********************************************************************* 464 * m48txx_nvram_probe(drv,a,b,ptr) 465 * 466 * Probe routine for this driver. This routine creates the 467 * local device context and attaches it to the driver list 468 * within CFE. 469 * 470 * Input parameters: 471 * drv - driver handle 472 * a,b - probe hints (longs) 473 * ptr - probe hint (pointer) 474 * 475 * Return value: 476 * nothing 477 ********************************************************************* */ 478static void m48txx_nvram_probe(cfe_driver_t *drv, 479 unsigned long probe_a, unsigned long probe_b, 480 void *probe_ptr) 481{ 482 m48txx_nvram_t *softc; 483 char descr[80]; 484 485 softc = (m48txx_nvram_t *) KMALLOC(sizeof(m48txx_nvram_t),0); 486 487 /* 488 * Probe_a is the NVRAM base address. 489 * Probe_b is the NVRAM region size. 490 * Probe_ptr is unused. 491 */ 492 493 softc->base_addr = (int)probe_a; 494 softc->dev_size = (int)probe_b; 495 softc->env_offset = 0; 496 softc->env_size = softc->dev_size; 497 softc->data = (volatile unsigned char*) UNCADDR(softc->base_addr); 498 /* PHYS_TO_XKSEG_UNCACHED(softc->base_addr); */ 499 500 xsprintf(descr,"%s at %x size %dKB", 501 drv->drv_description, 502 softc->base_addr, 503 softc->dev_size / 1024 ); 504 505 cfe_attach(drv,softc,NULL,descr); 506} 507 508 509 510/* ********************************************************************* 511 * m48txx_nvram_open(ctx) 512 * 513 * Open this device. For the X1240, we do a quick test 514 * read to be sure the device is out there. 515 * 516 * Input parameters: 517 * ctx - device context (can obtain our softc here) 518 * 519 * Return value: 520 * 0 if ok 521 * else error code 522 ********************************************************************* */ 523 524static int m48txx_nvram_open(cfe_devctx_t *ctx) 525{ 526 return 0; 527} 528 529/* ********************************************************************* 530 * m48txx_nvram_read(ctx,buffer) 531 * 532 * Read bytes from the device. 533 * 534 * Input parameters: 535 * ctx - device context (can obtain our softc here) 536 * buffer - buffer descriptor (target buffer, length, offset) 537 * 538 * Return value: 539 * number of bytes read 540 * -1 if an error occured 541 ********************************************************************* */ 542 543static int m48txx_nvram_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 544{ 545 m48txx_nvram_t *softc = ctx->dev_softc; 546 hsaddr_t bptr; 547 int blen; 548 int idx; 549 int b = 0; 550 551 bptr = buffer->buf_ptr; 552 blen = buffer->buf_length; 553 554 if ((buffer->buf_offset + blen) > softc->dev_size) return -1; 555 556 idx = (int) buffer->buf_offset; 557 558 while (blen > 0) { 559 b = softc->data[idx]; 560 hs_write8(bptr,(unsigned char) b); 561 bptr++; 562 blen--; 563 idx++; 564 } 565 566 buffer->buf_retlen = bptr - buffer->buf_ptr; 567 return (b < 0) ? -1 : 0; 568} 569 570/* ********************************************************************* 571 * m48txx_nvram_inpstat(ctx,inpstat) 572 * 573 * Test input (read) status for the device 574 * 575 * Input parameters: 576 * ctx - device context (can obtain our softc here) 577 * inpstat - input status descriptor to receive value 578 * 579 * Return value: 580 * 0 if ok 581 * -1 if an error occured 582 ********************************************************************* */ 583 584static int m48txx_nvram_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat) 585{ 586 inpstat->inp_status = 1; 587 588 return 0; 589} 590 591/* ********************************************************************* 592 * m48txx_nvram_write(ctx,buffer) 593 * 594 * Write bytes from the device. 595 * 596 * Input parameters: 597 * ctx - device context (can obtain our softc here) 598 * buffer - buffer descriptor (target buffer, length, offset) 599 * 600 * Return value: 601 * number of bytes read 602 * -1 if an error occured 603 ********************************************************************* */ 604 605static int m48txx_nvram_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 606{ 607 m48txx_nvram_t *softc = ctx->dev_softc; 608 hsaddr_t bptr; 609 int blen; 610 int idx; 611 int b = 0; 612 613 bptr = buffer->buf_ptr; 614 blen = buffer->buf_length; 615 616 if ((buffer->buf_offset + blen) > softc->dev_size) return -1; 617 618 idx = (int) buffer->buf_offset; 619 620 while (blen > 0) { 621 b = hs_read8(bptr); 622 bptr++; 623 softc->data[idx] = b; 624 blen--; 625 idx++; 626 } 627 628 buffer->buf_retlen = bptr - buffer->buf_ptr; 629 return (b < 0) ? -1 : 0; 630} 631 632/* ********************************************************************* 633 * m48txx_nvram_ioctl(ctx,buffer) 634 * 635 * Perform miscellaneous I/O control operations on the device. 636 * 637 * Input parameters: 638 * ctx - device context (can obtain our softc here) 639 * buffer - buffer descriptor (target buffer, length, offset) 640 * 641 * Return value: 642 * number of bytes read 643 * -1 if an error occured 644 ********************************************************************* */ 645 646static int m48txx_nvram_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 647{ 648 m48txx_nvram_t *softc = ctx->dev_softc; 649 nvram_info_t info; 650 651 switch ((int)buffer->buf_ioctlcmd) { 652 case IOCTL_NVRAM_GETINFO: 653 if (buffer->buf_length != sizeof(nvram_info_t)) return -1; 654 info.nvram_offset = softc->env_offset; 655 info.nvram_size = softc->env_size; 656 info.nvram_eraseflg = FALSE; 657 buffer->buf_retlen = sizeof(nvram_info_t); 658 hs_memcpy_to_hs(buffer->buf_ptr,&info,sizeof(info)); 659 return 0; 660 default: 661 return -1; 662 } 663} 664 665/* ********************************************************************* 666 * m48txx_nvram_close(ctx,buffer) 667 * 668 * Close the device. 669 * 670 * Input parameters: 671 * ctx - device context (can obtain our softc here) 672 * 673 * Return value: 674 * 0 if ok 675 * -1 if an error occured 676 ********************************************************************* */ 677 678static int m48txx_nvram_close(cfe_devctx_t *ctx) 679{ 680 return 0; 681} 682 683 684