On Sat, Feb 18, 2012 at 03:09 +1100, Jonathan Gray wrote:
> On Fri, Feb 17, 2012 at 04:20:25PM +0100, Michal Mazurek wrote:
> > I have an alix2d2 running OpenBSD 5.0. There are no hw.sensors.
> > The producer says there is an LM86 on board, which is supported by the
> > maxtmp driver. It appears the driver is present in generic. I tried starting
> > sensorsd but got:
> > daemon:Feb 17 13:12:04 T1 sensorsd[10445]: startup, system has 0 sensors
> >
> > How can I read the temperature of my alix2d2 running OpenBSD 5.0?
>
> There is no driver for the CS5535/CS5536 I2C controller the chip is connected
> to,
> it won't work till that is written.
>
[un]surprisingly it's actually the same as gscsio(4). here's a port
of that code to glxpcib(4). i don't have the hardware at hand, but
i encourage you to test (:
cheers
Index: dev/pci/files.pci
===================================================================
RCS file: /cvs/src/sys/dev/pci/files.pci,v
retrieving revision 1.281
diff -u -p -r1.281 files.pci
--- dev/pci/files.pci 15 Nov 2011 22:27:53 -0000 1.281
+++ dev/pci/files.pci 18 Feb 2012 23:03:52 -0000
@@ -807,6 +807,6 @@ attach itherm at pci
file dev/pci/itherm.c itherm
# AMD Geode CS5536 PCI-ISA bridge
-device glxpcib: isabus, gpiobus
+device glxpcib: isabus, gpiobus, i2cbus
attach glxpcib at pci
file dev/pci/glxpcib.c glxpcib
Index: dev/pci/glxpcib.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/glxpcib.c,v
retrieving revision 1.3
diff -u -p -r1.3 glxpcib.c
--- dev/pci/glxpcib.c 23 Oct 2010 17:42:57 -0000 1.3
+++ dev/pci/glxpcib.c 18 Feb 2012 23:03:52 -0000
@@ -28,6 +28,7 @@
#include <sys/device.h>
#include <sys/gpio.h>
#include <sys/timetc.h>
+#include <sys/rwlock.h>
#include <machine/bus.h>
#ifdef __i386__
@@ -35,6 +36,8 @@
#endif
#include <dev/gpio/gpiovar.h>
+#include <dev/i2c/i2cvar.h>
+
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
@@ -133,6 +136,34 @@
#define AMD5536_GPIO_IN_INVRT_EN 0x24 /* invert input */
#define AMD5536_GPIO_READ_BACK 0x30 /* read back value */
+/* SMB */
+#define MSR_LBAR_SMB DIVIL_LBAR_SMB
+#define MSR_SMB_SIZE 0x07
+#define MSR_SMB_ADDR_MASK 0xfff8
+#define AMD5536_SMB_SDA 0x00 /* serial data */
+#define AMD5536_SMB_STS 0x01 /* status */
+#define AMD5536_SMB_STS_SLVSTOP 0x80 /* slave stop */
+#define AMD5536_SMB_STS_SDAST 0x40 /* smb data status */
+#define AMD5536_SMB_STS_BER 0x20 /* bus error */
+#define AMD5536_SMB_STS_NEGACK 0x10 /* negative acknowledge */
+#define AMD5536_SMB_STS_MASTER 0x02 /* master */
+#define AMD5536_SMB_STS_XMIT 0x01 /* transmit or receive */
+#define AMD5536_SMB_CST 0x02 /* control status */
+#define AMD5536_SMB_CST_MATCH 0x04 /* address match */
+#define AMD5536_SMB_CST_BB 0x02 /* bus busy */
+#define AMD5536_SMB_CST_BUSY 0x01 /* busy */
+#define AMD5536_SMB_CTL1 0x03 /* control 1 */
+#define AMD5536_SMB_CTL1_ACK 0x10 /* receive acknowledge */
+#define AMD5536_SMB_CTL1_INTEN 0x04 /* interrupt enable */
+#define AMD5536_SMB_CTL1_STOP 0x02 /* stop */
+#define AMD5536_SMB_CTL1_START 0x01 /* start */
+#define AMD5536_SMB_ADDR 0x04 /* serial address */
+#define AMD5536_SMB_ADDR_SAEN 0x80 /* slave enable */
+#define AMD5536_SMB_CTL2 0x05 /* control 2 */
+#define AMD5536_SMB_CTL2_EN 0x01 /* enable clock */
+#define AMD5536_SMB_CTL2_FREQ 0x78 /* 100 kHz */
+#define AMD5536_SMB_CTL3 0x06 /* control 3 */
+
/*
* MSR registers we want to preserve accross suspend/resume
*/
@@ -151,12 +182,21 @@ struct glxpcib_softc {
uint64_t sc_msrsave[nitems(glxpcib_msrlist)];
-#if !defined(SMALL_KERNEL) && NGPIO > 0
+#ifndef SMALL_KERNEL
+#if NGPIO > 0
/* GPIO interface */
bus_space_tag_t sc_gpio_iot;
bus_space_handle_t sc_gpio_ioh;
struct gpio_chipset_tag sc_gpio_gc;
gpio_pin_t sc_gpio_pins[AMD5536_GPIO_NPINS];
+#endif
+ /* I2C interface */
+ bus_space_tag_t sc_smb_iot;
+ bus_space_handle_t sc_smb_ioh;
+ struct i2c_controller sc_smb_ic;
+ struct rwlock sc_smb_lck;
+
+ /* Watchdog */
int sc_wdog;
int sc_wdog_period;
#endif
@@ -180,11 +220,23 @@ void pcibattach(struct device *parent, s
u_int glxpcib_get_timecount(struct timecounter *tc);
-#if !defined(SMALL_KERNEL) && NGPIO > 0
+#ifndef SMALL_KERNEL
+int glxpcib_wdogctl_cb(void *, int);
+#if NGPIO > 0
void glxpcib_gpio_pin_ctl(void *, int, int);
int glxpcib_gpio_pin_read(void *, int);
void glxpcib_gpio_pin_write(void *, int, int);
-int glxpcib_wdogctl_cb(void *, int);
+#endif
+int glxpcib_smb_acquire_bus(void *, int);
+void glxpcib_smb_release_bus(void *, int);
+int glxpcib_smb_send_start(void *, int);
+int glxpcib_smb_send_stop(void *, int);
+void glxpcib_smb_send_ack(void *, int);
+int glxpcib_smb_initiate_xfer(void *, i2c_addr_t, int);
+int glxpcib_smb_read_byte(void *, uint8_t *, int);
+int glxpcib_smb_write_byte(void *, uint8_t, int);
+void glxpcib_smb_reset(struct glxpcib_softc *);
+int glxpcib_smb_wait(struct glxpcib_softc *, int, int);
#endif
const struct pci_matchid glxpcib_devices[] = {
@@ -208,12 +260,18 @@ glxpcib_attach(struct device *parent, st
{
struct glxpcib_softc *sc = (struct glxpcib_softc *)self;
struct timecounter *tc = &sc->sc_timecounter;
-#if !defined(SMALL_KERNEL) && NGPIO > 0
+#ifndef SMALL_KERNEL
struct pci_attach_args *pa = (struct pci_attach_args *)aux;
- u_int64_t wa, ga;
+ u_int64_t wa;
+#if NGPIO > 0
+ u_int64_t ga;
struct gpiobus_attach_args gba;
int i, gpio = 0;
#endif
+ u_int64_t sa;
+ struct i2cbus_attach_args iba;
+ int i2c = 0;
+#endif
tc->tc_get_timecount = glxpcib_get_timecount;
tc->tc_counter_mask = 0xffffffff;
tc->tc_frequency = 3579545;
@@ -230,7 +288,7 @@ glxpcib_attach(struct device *parent, st
(int)rdmsr(AMD5536_REV) & AMD5536_REV_MASK,
tc->tc_frequency);
-#if !defined(SMALL_KERNEL) && NGPIO > 0
+#ifndef SMALL_KERNEL
/* Attach the watchdog timer */
sc->sc_iot = pa->pa_iot;
wa = rdmsr(MSR_LBAR_MFGPT);
@@ -246,6 +304,7 @@ glxpcib_attach(struct device *parent, st
printf(", watchdog");
}
+#if NGPIO > 0
/* map GPIO I/O space */
sc->sc_gpio_iot = pa->pa_iot;
ga = rdmsr(MSR_LBAR_GPIO);
@@ -280,13 +339,71 @@ glxpcib_attach(struct device *parent, st
gpio = 1;
}
-#endif
+#endif /* NGPIO */
+
+ /* Map SMB I/O space */
+ sc->sc_smb_iot = pa->pa_iot;
+ sa = rdmsr(MSR_LBAR_SMB);
+ if (sa & MSR_LBAR_ENABLE &&
+ !bus_space_map(sc->sc_smb_iot, sa & MSR_SMB_ADDR_MASK,
+ MSR_SMB_SIZE, 0, &sc->sc_smb_ioh)) {
+ int freq = 0;
+ u_int8_t ctl, addr;
+
+ freq = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
+ AMD5536_SMB_CTL2) >> 1;
+ freq |= bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
+ AMD5536_SMB_CTL3) << 7;
+
+ /* Disable interrupts */
+ ctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
+ AMD5536_SMB_CTL1);
+ ctl &= ~AMD5536_SMB_CTL1_INTEN;
+ bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh,
+ AMD5536_SMB_CTL1, ctl);
+
+ /* Enable controller */
+ bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh,
+ AMD5536_SMB_CTL2, AMD5536_SMB_CTL2_EN |
+ AMD5536_SMB_CTL2_FREQ);
+
+ /* Disable slave address */
+ addr = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
+ AMD5536_SMB_ADDR);
+ addr &= ~AMD5536_SMB_ADDR_SAEN;
+ bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh,
+ AMD5536_SMB_ADDR, addr);
+
+ /* Attach I2C framework */
+ sc->sc_smb_ic.ic_cookie = sc;
+ sc->sc_smb_ic.ic_acquire_bus = glxpcib_smb_acquire_bus;
+ sc->sc_smb_ic.ic_release_bus = glxpcib_smb_release_bus;
+ sc->sc_smb_ic.ic_send_start = glxpcib_smb_send_start;
+ sc->sc_smb_ic.ic_send_stop = glxpcib_smb_send_stop;
+ sc->sc_smb_ic.ic_initiate_xfer = glxpcib_smb_initiate_xfer;
+ sc->sc_smb_ic.ic_read_byte = glxpcib_smb_read_byte;
+ sc->sc_smb_ic.ic_write_byte = glxpcib_smb_write_byte;
+
+ rw_init(&sc->sc_smb_lck, "iiclk");
+
+ bzero(&iba, sizeof(iba));
+ iba.iba_name = "iic";
+ iba.iba_tag = &sc->sc_smb_ic;
+ i2c = 1;
+
+ printf(", i2c freq=%#x", freq);
+ }
+#endif /* SMALL_KERNEL */
pcibattach(parent, self, aux);
-#if !defined(SMALL_KERNEL) && NGPIO > 0
+#ifndef SMALL_KERNEL
+#if NGPIO > 0
if (gpio)
config_found(&sc->sc_dev, &gba, gpiobus_print);
#endif
+ if (i2c)
+ config_found(&sc->sc_dev, &iba, iicbus_print);
+#endif
}
int
@@ -315,7 +432,6 @@ glxpcib_activate(struct device *self, in
for (i = 0; i < nitems(glxpcib_msrlist); i++)
sc->sc_msrsave[i] = rdmsr(glxpcib_msrlist[i]);
#endif
-
break;
case DVACT_RESUME:
#ifndef SMALL_KERNEL
@@ -336,7 +452,7 @@ glxpcib_get_timecount(struct timecounter
return rdmsr(AMD5536_TMC);
}
-#if !defined(SMALL_KERNEL) && NGPIO > 0
+#ifndef SMALL_KERNEL
int
glxpcib_wdogctl_cb(void *v, int period)
{
@@ -360,6 +476,7 @@ glxpcib_wdogctl_cb(void *v, int period)
return period;
}
+#if NGPIO > 0
int
glxpcib_gpio_pin_read(void *arg, int pin)
{
@@ -462,6 +579,189 @@ glxpcib_gpio_pin_ctl(void *arg, int pin,
for (n = 0; n < nreg; n++)
bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg[n],
val[n]);
-}
+}
+#endif /* GPIO */
-#endif
+int
+glxpcib_smb_acquire_bus(void *arg, int flags)
+{
+ struct glxpcib_softc *sc = arg;
+
+ if (cold || flags & I2C_F_POLL)
+ return (0);
+
+ return (rw_enter(&sc->sc_smb_lck, RW_WRITE | RW_INTR));
+}
+
+void
+glxpcib_smb_release_bus(void *arg, int flags)
+{
+ struct glxpcib_softc *sc = arg;
+
+ if (cold || flags & I2C_F_POLL)
+ return;
+
+ rw_exit(&sc->sc_smb_lck);
+}
+
+int
+glxpcib_smb_send_start(void *arg, int flags)
+{
+ struct glxpcib_softc *sc = arg;
+ u_int8_t ctl;
+
+ ctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
+ AMD5536_SMB_CTL1);
+ ctl |= AMD5536_SMB_CTL1_START;
+ bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL1,
+ ctl);
+
+ return (0);
+}
+
+int
+glxpcib_smb_send_stop(void *arg, int flags)
+{
+ struct glxpcib_softc *sc = arg;
+ u_int8_t ctl;
+
+ ctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
+ AMD5536_SMB_CTL1);
+ ctl |= AMD5536_SMB_CTL1_STOP;
+ bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL1,
+ ctl);
+
+ return (0);
+}
+
+void
+glxpcib_smb_send_ack(void *arg, int flags)
+{
+ struct glxpcib_softc *sc = arg;
+ u_int8_t ctl;
+
+ ctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
+ AMD5536_SMB_CTL1);
+ ctl |= AMD5536_SMB_CTL1_ACK;
+ bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL1,
+ ctl);
+}
+
+int
+glxpcib_smb_initiate_xfer(void *arg, i2c_addr_t addr, int flags)
+{
+ struct glxpcib_softc *sc = arg;
+ int error, dir;
+
+ /* Issue start condition */
+ glxpcib_smb_send_start(sc, flags);
+
+ /* Wait for bus mastership */
+ if ((error = glxpcib_smb_wait(sc, AMD5536_SMB_STS_MASTER |
+ AMD5536_SMB_STS_SDAST, flags)) != 0)
+ return (error);
+
+ /* Send address byte */
+ dir = (flags & I2C_F_READ ? 1 : 0);
+ bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_SDA,
+ (addr << 1) | dir);
+
+ return (0);
+}
+
+int
+glxpcib_smb_read_byte(void *arg, uint8_t *bytep, int flags)
+{
+ struct glxpcib_softc *sc = arg;
+ int error;
+
+ /* Wait for the bus to be ready */
+ if ((error = glxpcib_smb_wait(sc, AMD5536_SMB_STS_SDAST, flags)))
+ return (error);
+
+ /* Acknowledge the last byte */
+ if (flags & I2C_F_LAST)
+ glxpcib_smb_send_ack(sc, 0);
+
+ /* Read data byte */
+ *bytep = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
+ AMD5536_SMB_SDA);
+
+ return (0);
+}
+
+int
+glxpcib_smb_write_byte(void *arg, uint8_t byte, int flags)
+{
+ struct glxpcib_softc *sc = arg;
+ int error;
+
+ /* Wait for the bus to be ready */
+ if ((error = glxpcib_smb_wait(sc, AMD5536_SMB_STS_SDAST, flags)))
+ return (error);
+
+ /* Send stop after the last byte */
+ if (flags & I2C_F_STOP)
+ glxpcib_smb_send_stop(sc, 0);
+
+ /* Write data byte */
+ bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_ADDR,
+ byte);
+
+ return (0);
+}
+
+void
+glxpcib_smb_reset(struct glxpcib_softc *sc)
+{
+ u_int8_t st;
+
+ /* Clear MASTER, NEGACK and BER */
+ st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_STS);
+ st |= AMD5536_SMB_STS_MASTER | AMD5536_SMB_STS_NEGACK |
+ AMD5536_SMB_STS_BER;
+ bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_STS, st);
+
+ /* Disable and re-enable controller */
+ bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL2, 0);
+ bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, AMD5536_SMB_CTL2,
+ AMD5536_SMB_CTL2_EN | AMD5536_SMB_CTL2_FREQ);
+
+ /* Send stop */
+ glxpcib_smb_send_stop(sc, 0);
+}
+
+int
+glxpcib_smb_wait(struct glxpcib_softc *sc, int bits, int flags)
+{
+ u_int8_t st;
+ int i;
+
+ for (i = 0; i < 100; i++) {
+ st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
+ AMD5536_SMB_STS);
+ if (st & AMD5536_SMB_STS_BER) {
+ printf("%s: bus error, flags=%#x\n",
+ sc->sc_dev.dv_xname, flags);
+ glxpcib_smb_reset(sc);
+ return (EIO);
+ }
+ if (st & AMD5536_SMB_STS_NEGACK) {
+ printf("%s: negative ack, flags=%#x\n",
+ sc->sc_dev.dv_xname, flags);
+ glxpcib_smb_reset(sc);
+ return (EIO);
+ }
+ if ((st & bits) == bits)
+ break;
+ delay(10);
+ }
+ if ((st & bits) != bits) {
+ printf("%s: timeout, flags=%#x\n",
+ sc->sc_dev.dv_xname, flags);
+ glxpcib_smb_reset(sc);
+ return (ETIMEDOUT);
+ }
+ return (0);
+}
+#endif /* SMALL_KERNEL */