1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * BCM1250 SMBus controller driver File: sb1250_smbus.c 5 * 6 * Basic operations for BCM1250 SMBus controller. 7 * 8 * Author: Mitch Lichtenberg 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#include "cfe.h" 48#include "sbmips.h" 49 50#include "cfe_smbus.h" 51 52#include "sb1250_defs.h" 53#include "sb1250_regs.h" 54#include "sb1250_smbus.h" 55 56/* ********************************************************************* 57 * Types 58 ********************************************************************* */ 59 60 61typedef struct sb1250_smbus_softc_s { 62 long base; /* physical address of channel */ 63} sb1250_smbus_softc_t; 64 65/* ********************************************************************* 66 * Forward declarations 67 ********************************************************************* */ 68 69 70static int sb1250_smbus_qcmd(cfe_smbus_channel_t *chan,uint8_t slave,int rw); 71static int sb1250_smbus_xact(cfe_smbus_channel_t *chan,uint8_t slave,uint8_t cmd,uint8_t *buf,int len); 72static int sb1250_smbus_read(cfe_smbus_channel_t *chan,uint8_t slave,uint8_t *buf,int len); 73static int sb1250_smbus_write(cfe_smbus_channel_t *chan,uint8_t slave,uint8_t *buf,int len); 74static int sb1250_smbus_init(cfe_smbus_channel_t *chan); 75static cfe_smbus_channel_t *sb1250_smbus_attach(cfe_smbus_t *ops,uint64_t probe_a,uint64_t probe_b); 76 77/* 78 * SMBus Extended mode read write routines 79 */ 80 81static int sb1250_smbus_xread(cfe_smbus_channel_t *chan,uint8_t slave,uint8_t cmd,uint8_t numcmd,uint8_t numdat,int *buf); 82static int sb1250_smbus_xwrite(cfe_smbus_channel_t *chan,uint8_t slave,uint8_t cmd,uint8_t numcmd,uint8_t numdat,int *buf); 83 84/* ********************************************************************* 85 * SMBus operations 86 ********************************************************************* */ 87 88cfe_smbus_t sb1250_smbus = { 89 sb1250_smbus_attach, 90 sb1250_smbus_init, 91 sb1250_smbus_write, 92 sb1250_smbus_read, 93 sb1250_smbus_xact, 94 sb1250_smbus_qcmd, 95 sb1250_smbus_xread, 96 sb1250_smbus_xwrite 97}; 98 99 100static int sb1250_smbus_waitready(sb1250_smbus_softc_t *softc) 101{ 102 uint64_t status; 103 int cnt = 10000000; /* about 1 second at 1Ghz */ 104 105 while (cnt > 0) { 106 status = SBREADCSR(softc->base+R_SMB_STATUS); 107 if (status & M_SMB_BUSY) { 108 cnt--; 109 continue; 110 } 111 break; 112 } 113 114 if (cnt == 0) return CFE_ERR_TIMEOUT; 115 116 if (status & M_SMB_ERROR) { 117 SBWRITECSR(softc->base+R_SMB_STATUS,(status & M_SMB_ERROR)); 118 return CFE_ERR_NOTREADY; 119 } 120 return 0; 121} 122 123static cfe_smbus_channel_t *sb1250_smbus_attach(cfe_smbus_t *ops,uint64_t probe_a,uint64_t probe_b) 124{ 125 cfe_smbus_channel_t *chan; 126 sb1250_smbus_softc_t *softc; 127 128 chan = KMALLOC(sizeof(cfe_smbus_channel_t)+sizeof(sb1250_smbus_softc_t),0); 129 130 if (!chan) return NULL; 131 132 chan->ops = ops; 133 chan->softc = (void *) (chan+1); 134 135 softc = chan->softc; 136 softc->base = probe_a; 137 138 return chan; 139} 140 141static int sb1250_smbus_init(cfe_smbus_channel_t *chan) 142{ 143 sb1250_smbus_softc_t *softc = chan->softc; 144 145 /* 146 * Assume 100KHz for all devices. We don't need to go fast 147 * ever. 148 * 149 * Also turn off direct mode and disable interrupts. 150 */ 151 152 SBWRITECSR(softc->base+R_SMB_FREQ,K_SMB_FREQ_100KHZ); 153 SBWRITECSR(softc->base+R_SMB_CONTROL,0); 154 155 /* 156 * XXX Could switch to bit-bang mode here and send a bunch 157 * of null clocks to reset devices. 158 */ 159 160 return 0; 161} 162 163 164 165static int sb1250_smbus_write(cfe_smbus_channel_t *chan,uint8_t slave,uint8_t *buf,int len) 166{ 167 int err; 168 sb1250_smbus_softc_t *softc = chan->softc; 169 170 /* 171 * Make sure the bus is idle (ignore error here) 172 */ 173 174 sb1250_smbus_waitready(softc); 175 176 /* 177 * Depending on how many bytes we're writing, fill in the various 178 * SMB registers and execute the command. 179 */ 180 181 switch (len) { 182 case 1: /* "command" byte alone */ 183 SBWRITECSR(softc->base+R_SMB_CMD,buf[0]); 184 SBWRITECSR(softc->base+R_SMB_START,V_SMB_TT(K_SMB_TT_WR1BYTE) | ((uint64_t)slave)); 185 break; 186 case 2: /* "command" byte plus a data byte */ 187 SBWRITECSR(softc->base+R_SMB_CMD,buf[0]); 188 SBWRITECSR(softc->base+R_SMB_DATA,buf[1]); 189 SBWRITECSR(softc->base+R_SMB_START,V_SMB_TT(K_SMB_TT_WR2BYTE) | ((uint64_t)slave)); 190 break; 191 case 3: /* "command" byte plus 2 data bytes */ 192 SBWRITECSR(softc->base+R_SMB_CMD,buf[0]); 193 SBWRITECSR(softc->base+R_SMB_DATA,((uint64_t)(buf[1])) | (((uint64_t)buf[2]) << 8)); 194 SBWRITECSR(softc->base+R_SMB_START,V_SMB_TT(K_SMB_TT_WR3BYTE) | ((uint64_t)slave)); 195 break; 196 default: 197 return CFE_ERR_INV_PARAM; 198 break; 199 } 200 201 /* 202 * Wait for command to complete. 203 */ 204 205 err = sb1250_smbus_waitready(softc); 206 if (err < 0) return err; 207 208 return 0; 209} 210 211static int sb1250_smbus_read(cfe_smbus_channel_t *chan,uint8_t slave,uint8_t *buf,int len) 212{ 213 int err; 214 sb1250_smbus_softc_t *softc = chan->softc; 215 216 while (len > 0) { 217 err = sb1250_smbus_waitready(softc); 218 if (err < 0) return err; 219 220 SBWRITECSR(softc->base+R_SMB_START,V_SMB_TT(K_SMB_TT_RD1BYTE) | ((uint64_t)slave)); 221 222 err = sb1250_smbus_waitready(softc); 223 if (err < 0) return err; 224 225 *buf++ = (uint8_t) SBREADCSR(softc->base+R_SMB_DATA); 226 len--; 227 } 228 229 return 0; 230} 231 232static int sb1250_smbus_xwrite(cfe_smbus_channel_t *chan,uint8_t slave,uint8_t cmd,uint8_t numcmd,uint8_t numdat,int *buf) 233{ 234 sb1250_smbus_softc_t *softc = chan->softc; 235 int t; 236 int err ; 237 238 /* 239 * Make sure the bus is idle (ignore error here) 240 */ 241 242 sb1250_smbus_waitready(softc); 243 244 /* 245 * Do extended mode write access 246 */ 247 248 SBWRITECSR(softc->base+R_SMB_CMD,cmd); 249 t = buf[0] + (buf[1]<<8) ; 250 SBWRITECSR(softc->base+R_SMB_DATA,t); 251 // if numdat>2 SBWRITECSR(softc->base+R_SMB_?,ext); 252 253 SBWRITECSR(softc->base+ R_SMB_START, M_SMB_EXTEND | V_SMB_AFMT(numcmd) | V_SMB_DFMT(numdat) | ((uint64_t)slave)); 254 255 err = sb1250_smbus_waitready(softc); 256 if (err < 0) return err; 257 258 return 0; 259} 260 261static int sb1250_smbus_xread(cfe_smbus_channel_t *chan,uint8_t slave,uint8_t cmd,uint8_t numcmd,uint8_t numdat,int *buf) 262{ 263 sb1250_smbus_softc_t *softc = chan->softc; 264 265 /* 266 * Make sure the bus is idle (ignore error here) 267 */ 268 269 sb1250_smbus_waitready(softc); 270 271 /* 272 * Do extended mode read access 273 */ 274 275 SBWRITECSR(softc->base+R_SMB_CMD,cmd); 276 SBWRITECSR(softc->base+ R_SMB_START, M_SMB_EXTEND | M_SMB_DIR | V_SMB_AFMT(numcmd) | V_SMB_DFMT(numdat) | ((uint64_t)slave)); 277 278 sb1250_smbus_waitready(softc); 279 280 *buf = (int) SBREADCSR(softc->base+R_SMB_DATA); 281 282 return 0; 283} 284 285static int sb1250_smbus_xact(cfe_smbus_channel_t *chan,uint8_t slave,uint8_t cmd,uint8_t *buf,int len) 286{ 287 sb1250_smbus_softc_t *softc = chan->softc; 288 uint64_t data; 289 int err; 290 291 /* 292 * Make sure the bus is idle (ignore error here) 293 */ 294 295 sb1250_smbus_waitready(softc); 296 297 /* 298 * The "command" byte goes out... 299 */ 300 301 SBWRITECSR(softc->base+R_SMB_CMD,cmd); 302 303 /* 304 * And a variable number of bytes come back. 305 */ 306 307 switch (len) { 308 case 1: 309 SBWRITECSR(softc->base+R_SMB_START,V_SMB_TT(K_SMB_TT_CMD_RD1BYTE) | ((uint64_t)slave)); 310 break; 311 case 2: 312 SBWRITECSR(softc->base+R_SMB_START,V_SMB_TT(K_SMB_TT_CMD_RD2BYTE) | ((uint64_t)slave)); 313 break; 314 default: 315 return CFE_ERR_INV_PARAM; 316 } 317 318 err = sb1250_smbus_waitready(softc); 319 if (err < 0) return err; 320 321 /* 322 * Get data from device and unpack it for application. 323 */ 324 325 data = SBREADCSR(softc->base+R_SMB_DATA); 326 327 switch (len) { 328 case 1: 329 *buf++ = (data & 0xFF); 330 break; 331 case 2: 332 *buf++ = (data & 0xFF); 333 data >>= 8; 334 *buf++ = (data & 0xFF); 335 break; 336 } 337 338 return 0; 339 340} 341 342static int sb1250_smbus_qcmd(cfe_smbus_channel_t *chan,uint8_t slave,int rw) 343{ 344 int err; 345 sb1250_smbus_softc_t *softc = chan->softc; 346 347 /* 348 * Make sure the bus is idle (ignore error here) 349 */ 350 351 sb1250_smbus_waitready(softc); 352 353 SBWRITECSR(softc->base+R_SMB_START,V_SMB_TT(K_SMB_TT_QUICKCMD) | ((uint64_t)slave) | 354 (rw ? M_SMB_QDATA : 0)); 355 356 err = sb1250_smbus_waitready(softc); 357 358 return err; 359} 360