1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * Microchip 24lc128 EEPROM driver File: dev_sb1250_24lc128eeprom.c 5 * 6 * This module contains a CFE driver for a Microchip 24LC128 EEPROM 7 * 8 * Author: Mitch Lichtenberg (mpl@broadcom.com) 9 * 10 ********************************************************************* 11 * 12 * Copyright 2000,2001,2002,2003 13 * Broadcom Corporation. All rights reserved. 14 * 15 * This software is furnished under license and may be used and 16 * copied only in accordance with the following terms and 17 * conditions. Subject to these conditions, you may download, 18 * copy, install, use, modify and distribute modified or unmodified 19 * copies of this software in source and/or binary form. No title 20 * or ownership is transferred hereby. 21 * 22 * 1) Any source code used, modified or distributed must reproduce 23 * and retain this copyright notice and list of conditions 24 * as they appear in the source file. 25 * 26 * 2) No right is granted to use any trade name, trademark, or 27 * logo of Broadcom Corporation. The "Broadcom Corporation" 28 * name may not be used to endorse or promote products derived 29 * from this software without the prior written permission of 30 * Broadcom Corporation. 31 * 32 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 33 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 34 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 35 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 36 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 37 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 38 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 39 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 40 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 41 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 42 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 43 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 44 * THE POSSIBILITY OF SUCH DAMAGE. 45 ********************************************************************* */ 46 47 48#include "sbmips.h" 49#include "lib_types.h" 50#include "lib_malloc.h" 51#include "lib_printf.h" 52 53#include "cfe_iocb.h" 54#include "cfe_device.h" 55#include "cfe_ioctl.h" 56#include "cfe_timer.h" 57 58#include "sb1250_defs.h" 59#include "sb1250_regs.h" 60#include "sb1250_smbus.h" 61 62 63/* ********************************************************************* 64 * Forward Declarations 65 ********************************************************************* */ 66 67static void sb1250_24lc128eeprom_probe(cfe_driver_t *drv, 68 unsigned long probe_a, unsigned long probe_b, 69 void *probe_ptr); 70 71 72static int sb1250_24lc128eeprom_open(cfe_devctx_t *ctx); 73static int sb1250_24lc128eeprom_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 74static int sb1250_24lc128eeprom_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); 75static int sb1250_24lc128eeprom_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 76static int sb1250_24lc128eeprom_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 77static int sb1250_24lc128eeprom_close(cfe_devctx_t *ctx); 78 79/* ********************************************************************* 80 * Dispatch tables 81 ********************************************************************* */ 82 83#define M24LC128_EEPROM_SIZE 16384 84 85const static cfe_devdisp_t sb1250_24lc128eeprom_dispatch = { 86 sb1250_24lc128eeprom_open, 87 sb1250_24lc128eeprom_read, 88 sb1250_24lc128eeprom_inpstat, 89 sb1250_24lc128eeprom_write, 90 sb1250_24lc128eeprom_ioctl, 91 sb1250_24lc128eeprom_close, 92 NULL, 93 NULL 94}; 95 96const cfe_driver_t sb1250_24lc128eeprom = { 97 "Microchip 24LC128 EEPROM", 98 "eeprom", 99 CFE_DEV_NVRAM, 100 &sb1250_24lc128eeprom_dispatch, 101 sb1250_24lc128eeprom_probe 102}; 103 104typedef struct sb1250_24lc128eeprom_s { 105 int smbus_channel; 106 int smbus_address; 107 int env_offset; 108 int env_size; 109 unsigned char data[M24LC128_EEPROM_SIZE]; 110} sb1250_24lc128eeprom_t; 111 112 113/* ********************************************************************* 114 * smbus_init(chan) 115 * 116 * Initialize the specified SMBus channel 117 * 118 * Input parameters: 119 * chan - channel # (0 or 1) 120 * 121 * Return value: 122 * nothing 123 ********************************************************************* */ 124 125static void smbus_init(int chan) 126{ 127 uintptr_t reg; 128 129 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_FREQ)); 130 131 SBWRITECSR(reg,K_SMB_FREQ_100KHZ); 132 133 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_CONTROL)); 134 135 SBWRITECSR(reg,0); /* not in direct mode, no interrupts, will poll */ 136 137} 138 139/* ********************************************************************* 140 * smbus_waitready(chan) 141 * 142 * Wait until the SMBus channel is ready. We simply poll 143 * the busy bit until it clears. 144 * 145 * Input parameters: 146 * chan - channel (0 or 1) 147 * 148 * Return value: 149 * nothing 150 ********************************************************************* */ 151static int smbus_waitready(int chan) 152{ 153 uintptr_t reg; 154 uint64_t status; 155 156 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_STATUS)); 157 158 for (;;) { 159 status = SBREADCSR(reg); 160 if (status & M_SMB_BUSY) continue; 161 break; 162 } 163 164 if (status & M_SMB_ERROR) { 165 166 SBWRITECSR(reg,(status & M_SMB_ERROR)); 167 return -1; 168 } 169 return 0; 170} 171 172/* ********************************************************************* 173 * smbus_readbyte(chan,slaveaddr,devaddr) 174 * 175 * Read a byte from the chip. The 'slaveaddr' parameter determines 176 * whether we're reading from the RTC section or the EEPROM section. 177 * 178 * Input parameters: 179 * chan - SMBus channel 180 * slaveaddr - SMBus slave address 181 * devaddr - byte with in the device to read 182 * 183 * Return value: 184 * 0 if ok 185 * else -1 186 ********************************************************************* */ 187 188static int smbus_readbyte(int chan,int slaveaddr,int devaddr) 189{ 190 uintptr_t reg; 191 int err; 192 193 /* 194 * Make sure the bus is idle (probably should 195 * ignore error here) 196 */ 197 198 if (smbus_waitready(chan) < 0) return -1; 199 200 /* 201 * Write the device address to the controller. There are two 202 * parts, the high part goes in the "CMD" field, and the 203 * low part is the data field. 204 */ 205 206 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_CMD)); 207 SBWRITECSR(reg,((devaddr >> 8) & 0x3F)); 208 209 /* 210 * Write the data to the controller 211 */ 212 213 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_DATA)); 214 SBWRITECSR(reg,((devaddr & 0xFF) & 0xFF)); 215 216 /* 217 * Start the command 218 */ 219 220 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_START)); 221 SBWRITECSR(reg,V_SMB_TT(K_SMB_TT_WR2BYTE) | slaveaddr); 222 223 /* 224 * Wait till done 225 */ 226 227 err = smbus_waitready(chan); 228 if (err < 0) return err; 229 230 /* 231 * Read the data byte 232 */ 233 234 SBWRITECSR(reg,V_SMB_TT(K_SMB_TT_RD1BYTE) | slaveaddr); 235 236 err = smbus_waitready(chan); 237 if (err < 0) return err; 238 239 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_DATA)); 240 err = SBREADCSR(reg); 241 242 return (err & 0xFF); 243} 244 245/* ********************************************************************* 246 * smbus_writebyte(chan,slaveaddr,devaddr,b) 247 * 248 * write a byte from the chip. The 'slaveaddr' parameter determines 249 * whethe we're writing to the RTC section or the EEPROM section. 250 * 251 * Input parameters: 252 * chan - SMBus channel 253 * slaveaddr - SMBus slave address 254 * devaddr - byte with in the device to read 255 * b - byte to write 256 * 257 * Return value: 258 * 0 if ok 259 * else -1 260 ********************************************************************* */ 261 262 263static int smbus_writebyte(int chan,int slaveaddr,int devaddr,int b) 264{ 265 uintptr_t reg; 266 int err; 267 int64_t timer; 268 269 /* 270 * Make sure the bus is idle (probably should 271 * ignore error here) 272 */ 273 274 if (smbus_waitready(chan) < 0) return -1; 275 276 /* 277 * Write the device address to the controller. There are two 278 * parts, the high part goes in the "CMD" field, and the 279 * low part is the data field. 280 */ 281 282 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_CMD)); 283 SBWRITECSR(reg,((devaddr >> 8) & 0x3F)); 284 285 /* 286 * Write the data to the controller 287 */ 288 289 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_DATA)); 290 SBWRITECSR(reg,((devaddr & 0xFF) | ((b & 0xFF) << 8))); 291 292 /* 293 * Start the command. Keep pounding on the device until it 294 * submits or the timer expires, whichever comes first. The 295 * datasheet says writes can take up to 10ms, so we'll give it 500. 296 */ 297 298 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_START)); 299 SBWRITECSR(reg,V_SMB_TT(K_SMB_TT_WR3BYTE) | slaveaddr); 300 301 /* 302 * Wait till the SMBus interface is done 303 */ 304 305 err = smbus_waitready(chan); 306 if (err < 0) return err; 307 308 /* 309 * Pound on the device with a quick command (R/W=0) 310 * to poll for the write complete. See sect 7.0 of the 311 * 24LC128 manual. 312 */ 313 314 TIMER_SET(timer,50); 315 err = -1; 316 317 while (!TIMER_EXPIRED(timer)) { 318 POLL(); 319 320 SBWRITECSR(reg,V_SMB_TT(K_SMB_TT_QUICKCMD) | slaveaddr); 321 322 err = smbus_waitready(chan); 323 if (err == 0) break; 324 } 325 326 return err; 327} 328 329 330/* ********************************************************************* 331 * sb1250_24lc128eeprom_probe(drv,a,b,ptr) 332 * 333 * Probe routine for this driver. This routine creates the 334 * local device context and attaches it to the driver list 335 * within CFE. 336 * 337 * Input parameters: 338 * drv - driver handle 339 * a,b - probe hints (longs) 340 * ptr - probe hint (pointer) 341 * 342 * Return value: 343 * nothing 344 ********************************************************************* */ 345 346static void sb1250_24lc128eeprom_probe(cfe_driver_t *drv, 347 unsigned long probe_a, unsigned long probe_b, 348 void *probe_ptr) 349{ 350 sb1250_24lc128eeprom_t *softc; 351 char descr[80]; 352 353 softc = (sb1250_24lc128eeprom_t *) KMALLOC(sizeof(sb1250_24lc128eeprom_t),0); 354 355 /* 356 * Probe_a is the SMBus channel number 357 * Probe_b is the SMBus device offset 358 * Probe_ptr is unused. 359 */ 360 361 softc->smbus_channel = (int)probe_a; 362 softc->smbus_address = (int)probe_b; 363 softc->env_offset = 0; 364 softc->env_size = M24LC128_EEPROM_SIZE; 365 366 xsprintf(descr,"%s on SMBus channel %d dev 0x%02X", 367 drv->drv_description,(int)probe_a,(int)probe_b); 368 cfe_attach(drv,softc,NULL,descr); 369} 370 371 372 373/* ********************************************************************* 374 * sb1250_24lc128eeprom_open(ctx) 375 * 376 * Open this device. For the X1240, we do a quick test 377 * read to be sure the device is out there. 378 * 379 * Input parameters: 380 * ctx - device context (can obtain our softc here) 381 * 382 * Return value: 383 * 0 if ok 384 * else error code 385 ********************************************************************* */ 386 387static int sb1250_24lc128eeprom_open(cfe_devctx_t *ctx) 388{ 389 sb1250_24lc128eeprom_t *softc = ctx->dev_softc; 390 int b; 391 392 smbus_init(softc->smbus_channel); 393 394 b = smbus_readbyte(softc->smbus_channel, 395 softc->smbus_address, 396 0); 397 398 return (b < 0) ? -1 : 0; 399} 400 401/* ********************************************************************* 402 * sb1250_24lc128eeprom_read(ctx,buffer) 403 * 404 * Read bytes from the device. 405 * 406 * Input parameters: 407 * ctx - device context (can obtain our softc here) 408 * buffer - buffer descriptor (target buffer, length, offset) 409 * 410 * Return value: 411 * number of bytes read 412 * -1 if an error occured 413 ********************************************************************* */ 414 415static int sb1250_24lc128eeprom_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 416{ 417 sb1250_24lc128eeprom_t *softc = ctx->dev_softc; 418 unsigned char *bptr; 419 int blen; 420 int idx; 421 int b = 0; 422 423 bptr = buffer->buf_ptr; 424 blen = buffer->buf_length; 425 426 if ((buffer->buf_offset + blen) > M24LC128_EEPROM_SIZE) return -1; 427 428 idx = (int) buffer->buf_offset; 429 430 while (blen > 0) { 431 b = smbus_readbyte(softc->smbus_channel, 432 softc->smbus_address, 433 idx); 434 if (b < 0) break; 435 *bptr++ = (unsigned char) b; 436 blen--; 437 idx++; 438 } 439 440 buffer->buf_retlen = bptr - buffer->buf_ptr; 441 return (b < 0) ? -1 : 0; 442} 443 444/* ********************************************************************* 445 * sb1250_24lc128eeprom_inpstat(ctx,inpstat) 446 * 447 * Test input (read) status for the device 448 * 449 * Input parameters: 450 * ctx - device context (can obtain our softc here) 451 * inpstat - input status descriptor to receive value 452 * 453 * Return value: 454 * 0 if ok 455 * -1 if an error occured 456 ********************************************************************* */ 457 458static int sb1250_24lc128eeprom_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat) 459{ 460 inpstat->inp_status = 1; 461 462 return 0; 463} 464 465/* ********************************************************************* 466 * sb1250_24lc128eeprom_write(ctx,buffer) 467 * 468 * Write bytes from the device. 469 * 470 * Input parameters: 471 * ctx - device context (can obtain our softc here) 472 * buffer - buffer descriptor (target buffer, length, offset) 473 * 474 * Return value: 475 * number of bytes read 476 * -1 if an error occured 477 ********************************************************************* */ 478 479static int sb1250_24lc128eeprom_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 480{ 481 sb1250_24lc128eeprom_t *softc = ctx->dev_softc; 482 unsigned char *bptr; 483 int blen; 484 int idx; 485 int b = 0; 486 487 bptr = buffer->buf_ptr; 488 blen = buffer->buf_length; 489 490 if ((buffer->buf_offset + blen) > M24LC128_EEPROM_SIZE) return -1; 491 492 idx = (int) buffer->buf_offset; 493 494 while (blen > 0) { 495 b = *bptr++; 496 b = smbus_writebyte(softc->smbus_channel, 497 softc->smbus_address, 498 idx, 499 b); 500 if (b < 0) break; 501 blen--; 502 idx++; 503 } 504 505 buffer->buf_retlen = bptr - buffer->buf_ptr; 506 return (b < 0) ? -1 : 0; 507} 508 509/* ********************************************************************* 510 * sb1250_24lc128eeprom_ioctl(ctx,buffer) 511 * 512 * Perform miscellaneous I/O control operations on the device. 513 * 514 * Input parameters: 515 * ctx - device context (can obtain our softc here) 516 * buffer - buffer descriptor (target buffer, length, offset) 517 * 518 * Return value: 519 * number of bytes read 520 * -1 if an error occured 521 ********************************************************************* */ 522 523static int sb1250_24lc128eeprom_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 524{ 525 sb1250_24lc128eeprom_t *softc = ctx->dev_softc; 526 nvram_info_t *info; 527 528 switch ((int)buffer->buf_ioctlcmd) { 529 case IOCTL_NVRAM_GETINFO: 530 info = (nvram_info_t *) buffer->buf_ptr; 531 if (buffer->buf_length != sizeof(nvram_info_t)) return -1; 532 info->nvram_offset = softc->env_offset; 533 info->nvram_size = softc->env_size; 534 info->nvram_eraseflg = FALSE; 535 buffer->buf_retlen = sizeof(nvram_info_t); 536 return 0; 537 default: 538 return -1; 539 } 540} 541 542/* ********************************************************************* 543 * sb1250_24lc128eeprom_close(ctx,buffer) 544 * 545 * Close the device. 546 * 547 * Input parameters: 548 * ctx - device context (can obtain our softc here) 549 * 550 * Return value: 551 * 0 if ok 552 * -1 if an error occured 553 ********************************************************************* */ 554 555static int sb1250_24lc128eeprom_close(cfe_devctx_t *ctx) 556{ 557 return 0; 558} 559 560 561