Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/pc/piix4smbus.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname pc/piix4smbus.c 1999/0713
## diff -e /dev/null /n/emeliedump/1999/0713/sys/src/brazil/pc/piix4smbus.c
0a
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"

//
//	SMBus support for the PIIX4
//
enum
{
	IntelVendID=	0x8086,
	Piix4PMID=	0x7113,		/* PIIX4 power management function */

	// SMBus configuration registers (function 3)
	SMBbase=	0x90,		// 4 byte base address (bit 0 == 1, bit 3:1 == 0)
	SMBconfig=	0xd2,
	 SMBintrselect=	(7<<1),
	  SMIenable=	(0<<1),		//  interrupts sent to SMI#
	  IRQ9enable=	(4<<1),		//  intettupts sent to IRQ9
	 SMBenable=	(1<<0),		//  1 enables

	// SMBus IO space registers
	Hoststatus=	0x0,
	 Failed=	(1<<4),	 	//  transaction terminated by KILL (reset by writing 1)
	 Bus_error=	(1<<3),		//  transactio collision (reset by writing 1)
	 Dev_error=	(1<<2),		//  device error interrupt (reset by writing 1)
	 Host_complete=	(1<<2),		//  host command completion interrupt (reset by writing 1)
	 Host_busy=	(1<<0),		//
	Slavestatus=	0x1,
	 Alert_sts=	(1<<5),		//  someone asserted SMBALERT# (reset by writing 1)
	 Shdw2_sts=	(1<<4),		//  slave accessed shadow 2 port (reset by writing 1)
	 Shdw1_sts=	(1<<3),		//  slave accessed shadow 1 port (reset by writing 1)
	 Slv_sts=	(1<<2),		//  slave accessed shadow 1 port (reset by writing 1)
	 Slv_bsy=	(1<<0),
	Hostcontrol=	0x2,
	 Start=		(1<<6),		//  start execution
	 Cmd_prot=	(7<<2),		//  command protocol mask
	  Quick=	(0<<2),		//   address only
	  Byte=		(1<<2),		//   address + cmd
	  ByteData=	(2<<2),		//   address + cmd + data
	  WordData=	(3<<2),		//   address + cmd + data + data
	 Kill=		(1<<1),		//  abort in progress command
	 Ienable=	(1<<0),		//  enable completion interrupts
	Hostcommand=	0x3,
	Hostaddress=	0x4,
	 AddressMask=	(0x7f<<1),	//  target address
	 RW=		(1<<0),		//  1 == read, 0 == write
	Hostdata0=	0x5,
	Hostdata1=	0x6,
	Blockdata=	0x7,
	Slavecontrol=	0x8,
	 Alert_en=	(1<<3),		//  enable interrupt on SMBALERT#
	 Shdw2_en=	(1<<2),		//  enable interrupt on external shadow 2 access
	 Shdw1_en=	(1<<1),		//  enable interrupt on external shadow 1 access
	 Slv_en=	(1<<0),		//  enable interrupt on access of host controller slave port
	Shadowcommand=	0x9,
	Slaveevent=	0xa,
	Slavedata=	0xc,
};

static int
quickcommand(SMBus *s, int addr)
{
}

static int
send(SMBus *s, int addr, int data)
{
}

static int
recv(SMBus *s, int addr. int *data)
{
}

static int
bytewrite(SMBus *s, int addr, int cmd, int data)
{
}

static int
byteread(SMBus *s, int addr, int cmd. int *data)
{
}

static int
wordwrite(SMBus *s, int addr, int cmd, int data)
{
}

static int
wordread(SMBus *s, int addr, int cmd. int *data)
{
}

static SMBus proto =
{
	.quick = quick,
	.send = send,
	.recv = recv,
	.bytewrite = bytewrite,
	.byteread = byteread,
	.wordwrite = wordwrite,
	.wordread = wordread,
};

//
//  return 0 if this is a piix4 with an smbus interface
//
SMBus*
piix4smbus(void)
{
	int pcs;
	Pcidev *p;
	static SMBus *s;

	if(s != nil)
		return s;

	p = pcimatch(p, IntelVendID, Piix4PMID));
	if(p == nil)
		return nil;

	s = smalloc(sizeof(*s));	
	memmove(s, &proto, sizeof(*s));
	s->arg = p;

	pcicfgw8(p->tbdf, SMBconfig, IRQ9enable|0);		// disable the smbus
	pcicfgw8(p->tbdf, SMBbase, 0x50);			// default address
	pcicfgw8(p->tbdf, SMBconfig, IRQ9enable|SMBenable);	// enable the smbus

	return s;
}
.
## diffname pc/piix4smbus.c 1999/0715
## diff -e /n/emeliedump/1999/0713/sys/src/brazil/pc/piix4smbus.c /n/emeliedump/1999/0715/sys/src/brazil/pc/piix4smbus.c
129,131c
	// disable the smbus
	pcicfgw8(p, SMBconfig, IRQ9enable|0);

	// see if bios gave us a viable port space
	s->base = pcicfgr32(p, SMBbase) & ~1;
print("SMB base from bios is 0x%lux\n", s->base);
	if(ioalloc(s->base, 0xd, 0, "piix4smbus") < 0){
		s->base = ioalloc(-1, 0xd, 2, "piix4smbus");
		if(s->base < 0){
			free(s);
			print("piix4smbus: can't allocate io port\n");
			return nil;
		}
print("SMB base ialloc is 0x%lux\n", s->base);
		pcicfgw32(p, SMBbase, s->base|1);
	}

	// disable SMBus interrupts, abort any transaction in progress
	pcicfgw8(p, Hostcontrol, Kill);
	pcicfgw8(p, Slavecontrol, 0);

	// enable the smbus
	pcicfgw8(p, SMBconfig, IRQ9enable|SMBenable);
.
126c
	memmove(s, &smbusproto, sizeof(*s));
.
121c
	p = pcimatch(nil, IntelVendID, Piix4PMID);
.
114d
99,105c
	.transact = transact,
.
97c
static SMBus smbusproto =
.
92,94c
	if(waserror()){
		qunlock(s);
		nexterror();
	}
	qlock(s);

	// wait a while for the host interface to be available
	if(spin(p, Host_busy) != 0){
		// try aborting current transaction
		pcicfgw8(p, Hostcontrol, Kill);
		if(spin(p, Host_busy) < 0)
			error("SMBus broken");
	}

	// set up for transaction
	pcicfgw8(p, Hostaddress, (addr<<1)|proto[type].rw);
	if(proto[type].cmd)
		pcicfgw8(p, Hostcommand, cmd);
	if(proto[type].rw != Read){
		switch(proto[type].len){
		case 2:
			pcicfgw8(p, Hostdata1, data[1]);
			// fall through
		case 1:
			pcicfgw8(p, Hostdata0, data[0]);
			break;
		}
	}

	// reset the completion bit and start transaction
	pcicfgw8(p, Hoststatus, Host_complete);
	pcicfgw8(p, Hostcontrol, Start|proto[type].proto);

	// wait for completion
	if(spin(p, Host_complete) < 0)
		error("SMBus broken");

	// get results
	if(proto[type].rw == Read){
		switch(proto[type].len){
		case 2:
			data[1] = pcicfgr8(p, Hostdata1);
			// fall through
		case 1:
			data[0] = pcicfgr8(p, Hostdata0);
			break;
		}
	}
	qunlock(s);
.
87,90c
	if(type < 0 || type > nelem(proto))
		panic("piix4smbus: illegal transaction type %d", type);
.
85c
	Pcidev *p = s->arg;
.
82,83c
static void
transact(SMBus *s, int type, int addr, int cmd, uchar *data)
.
77,79c
	for(tries = 0; tries < 1000000; tries++){
		if((pcicfgr8(p, Hoststatus) & bit) == 0)
			return 0;
		sched();
	}
	return -1;
.
75c
	int tries;
.
73c
spin(Pcidev *p, int bit)
.
70c
	[SMBquick]	{ 0,	0,	0,	Quick },
	[SMBsend]	{ 0,	1,	0,	Byte },
	[SMBbytewrite]	{ 0,	1,	1,	ByteData },
	[SMBwordwrite]	{ 0,	1,	2,	WordData },
	[SMBrecv]	{ Read,	1,	0, 	Byte },
	[SMBbyteread]	{ Read,	1,	1,	ByteData },
	[SMBwordread]	{ Read,	1,	2,	WordData },
};
.
65,68c
	int	rw;
	int	cmd;
	int	len;
	int	proto;
} proto[] =
.
62,63c
static struct
.
53,56c
	 Alert_en=	(1<<3),		//  enable inter on SMBALERT#
	 Shdw2_en=	(1<<2),		//  enable inter on external shadow 2 access
	 Shdw1_en=	(1<<1),		//  enable inter on external shadow 1 access
	 Slv_en=	(1<<0),		//  enable inter on access of host ctlr slave port
.
48c
	 Read=		(1<<0),		//  1 == read, 0 == write
.
30,34c
	Slavestatus=	0x1,		//  (writing 1 bits reset)
	 Alert_sts=	(1<<5),		//  someone asserted SMBALERT#
	 Shdw2_sts=	(1<<4),		//  slave accessed shadow 2 port
	 Shdw1_sts=	(1<<3),		//  slave accessed shadow 1 port
	 Slv_sts=	(1<<2),		//  slave accessed shadow 1 port
.
24,28c
	Hoststatus=	0x0,		//  (writing 1 bits reset the interrupt bits)
	 Failed=	(1<<4),	 	//  transaction terminated by KILL
	 Bus_error=	(1<<3),		//  transactio collision
	 Dev_error=	(1<<2),		//  device error interrupt
	 Host_complete=	(1<<2),		//  host command completion interrupt 
.
5a
#include	"io.h"
.
## diffname pc/piix4smbus.c 1999/0725
## diff -e /n/emeliedump/1999/0715/sys/src/brazil/pc/piix4smbus.c /n/emeliedump/1999/0725/sys/src/brazil/pc/piix4smbus.c
195,196c
	outb(s->base+Hostcontrol, Kill);
	outb(s->base+Slavecontrol, 0);
.
149a
	poperror();
.
145c
			data[0] = inb(s->base+Hostdata0);
.
142c
			data[1] = inb(s->base+Hostdata1);
.
135,136c
	for(tries = 0; tries < 1000000; tries++){
		if(inb(s->base+Hoststatus) & Host_complete)
			break;
		sched();
	}
	if(tries >= 1000000){
		print("SMBus status: %2.2ux", inb(s->base+Hoststatus));
		error("SMBus broken2");
	}
.
131,132c
	outb(s->base+Hoststatus, Host_complete);
print("before %2.2ux\n", inb(s->base+Hoststatus));
	outb(s->base+Hostcontrol, Start|proto[type].proto);
print("after %2.2ux\n", inb(s->base+Hoststatus));
.
125c
			outb(s->base+Hostdata0, data[0]);
.
122c
			outb(s->base+Hostdata1, data[1]);
.
118c
		outb(s->base+Hostcommand, cmd);
.
116c
	outb(s->base+Hostaddress, (addr<<1)|proto[type].rw);
.
110,112c
		outb(s->base+Hostcontrol, Kill);
		for(tries = 0; tries < 1000000; tries++){
			if((inb(s->base+Hoststatus) & Host_busy) == 0)
				break;
			sched();
		}
		if(tries >= 1000000){
			print("SMBus status: %2.2ux", inb(s->base+Hoststatus));
			error("SMBus broken1");
		}
.
108c
	for(tries = 0; tries < 1000000; tries++){
		if((inb(s->base+Hoststatus) & Host_busy) == 0)
			break;
		sched();
	}
	if(tries >= 1000000){
.
96c
	int tries;
.
80,92d
75c
	[SMBrecv]	{ Read,	0,	1, 	Byte },
.
29c
	 Host_complete=	(1<<1),		//  host command completion interrupt 
.
## diffname pc/piix4smbus.c 1999/0726
## diff -e /n/emeliedump/1999/0725/sys/src/brazil/pc/piix4smbus.c /n/emeliedump/1999/0726/sys/src/brazil/pc/piix4smbus.c
141,143c
	if((status & Host_complete) == 0){
		snprint(err, sizeof(err), "SMBus request failed: %2.2ux", status);
		error(err);
.
137c
		status = inb(s->base+Hoststatus);
		if(status & (Failed|Bus_error|Dev_error|Host_complete))
.
133d
129,131c
	// reset the completion/error bits and start transaction
	outb(s->base+Hoststatus, Failed|Bus_error|Dev_error|Host_complete);
.
127a
	 
.
109,110c
			snprint(err, sizeof(err), "SMBus jammed: %2.2ux", inb(s->base+Hoststatus));
			error(err);
.
83c
	int tries, status;
	char err[ERRLEN];
.
## diffname pc/piix4smbus.c 1999/0916
## diff -e /n/emeliedump/1999/0726/sys/src/brazil/pc/piix4smbus.c /n/emeliedump/1999/0916/sys/src/brazil/pc/piix4smbus.c
135a
	status = 0;
.

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].