⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sb1250_smbus.c

📁 一个很好的嵌入式linux平台下的bootloader
💻 C
字号:
/*  *********************************************************************    *  Broadcom Common Firmware Environment (CFE)    *      *  BCM1250 SMBus controller driver		File: sb1250_smbus.c    *      *  Basic operations for BCM1250 SMBus controller.    *      *  Author:  Mitch Lichtenberg    *      *********************************************************************      *    *  Copyright 2000,2001,2002,2003    *  Broadcom Corporation. All rights reserved.    *      *  This software is furnished under license and may be used and     *  copied only in accordance with the following terms and     *  conditions.  Subject to these conditions, you may download,     *  copy, install, use, modify and distribute modified or unmodified     *  copies of this software in source and/or binary form.  No title     *  or ownership is transferred hereby.    *      *  1) Any source code used, modified or distributed must reproduce     *     and retain this copyright notice and list of conditions     *     as they appear in the source file.    *      *  2) No right is granted to use any trade name, trademark, or     *     logo of Broadcom Corporation.  The "Broadcom Corporation"     *     name may not be used to endorse or promote products derived     *     from this software without the prior written permission of     *     Broadcom Corporation.    *      *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR    *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED    *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR     *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT     *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN     *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,    *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES     *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE    *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR    *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY     *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR     *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF     *     THE POSSIBILITY OF SUCH DAMAGE.    ********************************************************************* */#include "cfe.h"#include "sbmips.h"#include "cfe_smbus.h"#include "sb1250_defs.h"#include "sb1250_regs.h"#include "sb1250_smbus.h"/*  *********************************************************************    *  Types    ********************************************************************* */typedef struct sb1250_smbus_softc_s {    long base;				/* physical address of channel */} sb1250_smbus_softc_t;/*  *********************************************************************    *  Forward declarations    ********************************************************************* */static int sb1250_smbus_qcmd(cfe_smbus_channel_t *chan,uint8_t slave,int rw);static int sb1250_smbus_xact(cfe_smbus_channel_t *chan,uint8_t slave,uint8_t cmd,uint8_t *buf,int len);static int sb1250_smbus_read(cfe_smbus_channel_t *chan,uint8_t slave,uint8_t *buf,int len);static int sb1250_smbus_write(cfe_smbus_channel_t *chan,uint8_t slave,uint8_t *buf,int len);static int sb1250_smbus_init(cfe_smbus_channel_t *chan);static cfe_smbus_channel_t *sb1250_smbus_attach(cfe_smbus_t *ops,uint64_t probe_a,uint64_t probe_b);/*  *********************************************************************    *  SMBus operations    ********************************************************************* */cfe_smbus_t sb1250_smbus = {    sb1250_smbus_attach,    sb1250_smbus_init,    sb1250_smbus_write,    sb1250_smbus_read,    sb1250_smbus_xact,    sb1250_smbus_qcmd};static int sb1250_smbus_waitready(sb1250_smbus_softc_t *softc){    uint64_t status;    int cnt  = 10000000;	/* about 1 second at 1Ghz */    while (cnt > 0) {	status = SBREADCSR(softc->base+R_SMB_STATUS);	if (status & M_SMB_BUSY) {	    cnt--;	    continue;	    }	break;	}    if (cnt == 0) return CFE_ERR_TIMEOUT;    if (status & M_SMB_ERROR) {	SBWRITECSR(softc->base+R_SMB_STATUS,(status & M_SMB_ERROR));	return CFE_ERR_NOTREADY;	}    return 0;}static cfe_smbus_channel_t *sb1250_smbus_attach(cfe_smbus_t *ops,uint64_t probe_a,uint64_t probe_b){    cfe_smbus_channel_t *chan;	    sb1250_smbus_softc_t *softc;    chan = KMALLOC(sizeof(cfe_smbus_channel_t)+sizeof(sb1250_smbus_softc_t),0);    if (!chan) return NULL;    chan->ops = ops;    chan->softc = (void *) (chan+1);    softc = chan->softc;    softc->base = probe_a;    return chan;}static int sb1250_smbus_init(cfe_smbus_channel_t *chan){    sb1250_smbus_softc_t *softc = chan->softc;    /*     * Assume 100KHz for all devices.  We don't need to go fast     * ever.     *     * Also turn off direct mode and disable interrupts.     */    SBWRITECSR(softc->base+R_SMB_FREQ,K_SMB_FREQ_100KHZ);    SBWRITECSR(softc->base+R_SMB_CONTROL,0);    /*     * XXX Could switch to bit-bang mode here and send a bunch     * of null clocks to reset devices.     */    return 0;}static int sb1250_smbus_write(cfe_smbus_channel_t *chan,uint8_t slave,uint8_t *buf,int len){    int err;    sb1250_smbus_softc_t *softc = chan->softc;    /*     * Make sure the bus is idle (ignore error here)     */    sb1250_smbus_waitready(softc);    /*     * Depending on how many bytes we're writing, fill in the various     * SMB registers and execute the command.     */    switch (len) {	case 1:		/* "command" byte alone */	    SBWRITECSR(softc->base+R_SMB_CMD,buf[0]);	    SBWRITECSR(softc->base+R_SMB_START,V_SMB_TT(K_SMB_TT_WR1BYTE) | ((uint64_t)slave));	    break;	case 2:		/* "command" byte plus a data byte */	    SBWRITECSR(softc->base+R_SMB_CMD,buf[0]);	    SBWRITECSR(softc->base+R_SMB_DATA,buf[1]);	    SBWRITECSR(softc->base+R_SMB_START,V_SMB_TT(K_SMB_TT_WR2BYTE) | ((uint64_t)slave));	    break;	case 3:		/* "command" byte plus 2 data bytes */	    SBWRITECSR(softc->base+R_SMB_CMD,buf[0]);	    SBWRITECSR(softc->base+R_SMB_DATA,((uint64_t)(buf[1])) | (((uint64_t)buf[2]) << 8));	    SBWRITECSR(softc->base+R_SMB_START,V_SMB_TT(K_SMB_TT_WR3BYTE) | ((uint64_t)slave));	    break;	default:	    return CFE_ERR_INV_PARAM;	    break;	}    /*     * Wait for command to complete.     */    err = sb1250_smbus_waitready(softc);    if (err < 0) return err;    return 0;}static int sb1250_smbus_read(cfe_smbus_channel_t *chan,uint8_t slave,uint8_t *buf,int len){    int err;    sb1250_smbus_softc_t *softc = chan->softc;    while (len > 0) {	err = sb1250_smbus_waitready(softc);	if (err < 0) return err;	SBWRITECSR(softc->base+R_SMB_START,V_SMB_TT(K_SMB_TT_RD1BYTE) | ((uint64_t)slave));	err = sb1250_smbus_waitready(softc);	if (err < 0) return err;	*buf++ = (uint8_t) SBREADCSR(softc->base+R_SMB_DATA);	len--;	}    return 0;}static int sb1250_smbus_xact(cfe_smbus_channel_t *chan,uint8_t slave,uint8_t cmd,uint8_t *buf,int len){    sb1250_smbus_softc_t *softc = chan->softc;    uint64_t data;    int err;    /*     * Make sure the bus is idle (ignore error here)     */    sb1250_smbus_waitready(softc);    /*     * The "command" byte goes out...     */    SBWRITECSR(softc->base+R_SMB_CMD,cmd);    /*     * And a variable number of bytes come back.     */    switch (len) {	case 1:	    SBWRITECSR(softc->base+R_SMB_START,V_SMB_TT(K_SMB_TT_CMD_RD1BYTE) | ((uint64_t)slave));	    break;	case 2:	    SBWRITECSR(softc->base+R_SMB_START,V_SMB_TT(K_SMB_TT_CMD_RD2BYTE) | ((uint64_t)slave));	    break;	default:	    return CFE_ERR_INV_PARAM;	}    err = sb1250_smbus_waitready(softc);    if (err < 0) return err;    /*     * Get data from device and unpack it for application.     */    data = SBREADCSR(softc->base+R_SMB_DATA);    switch (len) {	case 1:		    *buf++ = (data & 0xFF);	    break;	case 2:	    *buf++ = (data & 0xFF);	    data >>= 8;	    *buf++ = (data & 0xFF);	    break;	}        return 0;}static int sb1250_smbus_qcmd(cfe_smbus_channel_t *chan,uint8_t slave,int rw){    int err;    sb1250_smbus_softc_t *softc = chan->softc;    /*     * Make sure the bus is idle (ignore error here)     */    sb1250_smbus_waitready(softc);    SBWRITECSR(softc->base+R_SMB_START,V_SMB_TT(K_SMB_TT_QUICKCMD) | ((uint64_t)slave) |	       (rw ? M_SMB_QDATA : 0));    err = sb1250_smbus_waitready(softc);    return err;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -