Hi,
came across some old crap i had using mgiic on arm, as the IP on
sunxis is actually from Mentor Graphics, not Marvell.
What is in the diff below is not finished for either however, for
sparc64 it'll likely remain broken because of missing delays, and
for !sparc64(=armv7&arm64) i haven't verified anything yet.
Should i move it to dev/ic, w/slim wrappers in sys/arch/sparc64/dev
and sys/dev/fdt/ or? or just let it rot?
-Artturi
diff --git a/sys/arch/sparc64/dev/mgiic.c b/home/aalm/mgiic.c
index 6d1206a95f4..2ea255e62c9 100644
--- a/sys/arch/sparc64/dev/mgiic.c
+++ b/home/aalm/mgiic.c
@@ -25,11 +25,22 @@
#include <uvm/uvm_extern.h>
#include <machine/bus.h>
+#ifdef __sparc64__
#include <machine/autoconf.h>
#include <machine/openfirm.h>
#include <dev/i2c/i2cvar.h>
#include <sparc64/dev/ofwi2cvar.h>
+#else
+#include <machine/fdt.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_clock.h>
+#include <dev/ofw/ofw_pinctrl.h>
+#include <dev/ofw/fdt.h>
+
+#include <dev/i2c/i2cvar.h>
+#endif
#define MGSLAVEADDR 0x00
#define MGSLAVEXADDR 0x08
@@ -62,6 +73,15 @@
#define MGCLOCKCONTROL 0x28
#define MGSOFTRESET 0x30
+#define MGPOLLDELAY 1
+#define MGRDWRDELAY 2
+
+#ifndef MGIICDEBUG
+#define DPRINTF(a) do {/* NO-OP */} while (0)
+#else
+#define DPRINTF(a) printf a
+#endif
+
struct mgiic_softc {
struct device sc_dev;
@@ -69,6 +89,9 @@ struct mgiic_softc {
bus_space_handle_t sc_regh;
+#ifndef __sparc64__
+ void *sc_ih;
+#endif
int sc_poll;
struct i2c_controller sc_i2c;
@@ -94,8 +117,23 @@ int mgiic_i2c_exec(void *, i2c_op_t,
i2c_addr_t, const void *,
int mgiic_xmit(struct mgiic_softc *, u_int8_t, const
u_int8_t *,
size_t);
int mgiic_recv(struct mgiic_softc *, u_int8_t, u_int8_t *,
size_t);
+#ifdef __sparc64__
volatile u_int8_t mgiic_read(struct mgiic_softc *, bus_size_t);
volatile void mgiic_write(struct mgiic_softc *, bus_size_t, u_int8_t);
+#else
+int mgiic_intr(void *);
+volatile u_int8_t _mgiic_read(struct mgiic_softc *, bus_size_t);
+volatile void _mgiic_write(struct mgiic_softc *, bus_size_t,
u_int8_t);
+#define mgiic_read(sc,r) _mgiic_read_((sc), ((r) >> 1))
+#define mgiic_write(sc,r,v) _mgiic_write((sc), ((r) >> 1), (v))
+#define mainbus_attach_args fdt_attach_args
+#define ma_bustag fa_iot
+#define ma_reg fa_reg
+#define ur_paddr addr
+#define ur_len size
+#define ma_node fa_node
+#endif
+
volatile void mgiic_control(struct mgiic_softc *, u_int8_t, u_int8_t);
int mgiic_poll(struct mgiic_softc *);
@@ -103,6 +141,7 @@ int
mgiic_match(struct device *parent, void *match, void *aux)
{
struct mainbus_attach_args *ma = aux;
+#ifdef __sparc64__
char compat[32];
if (strcmp(ma->ma_name, "i2c") != 0)
@@ -112,6 +151,10 @@ mgiic_match(struct device *parent, void *match, void *aux)
if (strcmp(compat, "fire-i2c") == 0)
return (1);
return (0);
+#else
+ return (OF_is_compatible(ma->fa_node, "allwinner,sun4i-a10-i2c") ||
+ OF_is_compatible(ma->fa_node, "allwinner,sun7i-a20-i2c"));
+#endif
}
void
@@ -135,6 +178,31 @@ mgiic_attach(struct device *parent, struct device *self,
void *aux)
sc->sc_i2c.ic_release_bus = mgiic_i2c_release_bus;
sc->sc_i2c.ic_exec = mgiic_i2c_exec;
+#ifndef __sparc64__
+ pinctrl_byname(ma->fa_node, "default");
+
+ /* Enable clock */
+ clock_enable(ma->fa_node, NULL);
+
+ /*
+ * Set clock rate to 100kHz. From the datasheet:
+ * For 100Khz standard speed 2Wire, CLK_N=2, CLK_M=11
+ * F0=48M/2^2=12Mhz, F1=F0/(10*(11+1)) = 0.1Mhz
+ */
+ mgiic_write(sc, MGCLOCKCONTROL, (11 << 3) | (2 << 0));
+
+ /* Put the controller into Soft Reset. */
+ mgiic_write(sc, MGSOFTRESET, 0);
+
+ /* Establish interrupt */
+ sc->sc_ih = arm_intr_establish_fdt(ma->fa_node, IPL_BIO,
+ mgiic_intr, sc, sc->sc_dev.dv_xname);
+ if (sc->sc_ih == NULL) {
+ printf(": failed to establish interrupt\n");
+ return;
+ }
+#endif
+
printf("\n");
bzero(&iba, sizeof(iba));
@@ -193,7 +261,7 @@ mgiic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr,
ret = mgiic_recv(sc, addr & 0x7f, buf, len);
}
done:
- printf("e%d\n", ret);
+ DPRINTF(("e%d\n", ret));
return (ret);
}
@@ -201,38 +269,40 @@ int
mgiic_xmit(struct mgiic_softc *sc, u_int8_t addr, const u_int8_t *buf,
size_t len)
{
- int err = 1, i = 0;
+ int err = 1, i = 0, sta = 0;
top:
- printf("xmit s%02x STA ", mgiic_read(sc, MGSTATUS));
+ DPRINTF(("xmit s%02x STA ", mgiic_read(sc, MGSTATUS)));
mgiic_control(sc, MGCONTROL_STA, MGCONTROL_IFLG);
if (mgiic_poll(sc))
goto bail;
- printf("s%02x ", mgiic_read(sc, MGSTATUS));
- if (mgiic_read(sc, MGSTATUS) != MGSTATUS_STARTSENT)
+ sta = mgiic_read(sc, MGSTATUS);
+ DPRINTF(("s%02x ", sta));
+ if (sta != MGSTATUS_STARTSENT)
goto bail;
mgiic_write(sc, MGDATA, addr << 1);
- printf("a%02x ", addr << 1);
+ DPRINTF(("a%02x ", addr << 1));
mgiic_control(sc, 0, MGCONTROL_IFLG);
while (i < len) {
if (mgiic_poll(sc))
goto bail;
- printf("s%02x ", mgiic_read(sc, MGSTATUS));
- switch (mgiic_read(sc, MGSTATUS)) {
+ sta = mgiic_read(sc, MGSTATUS);
+ DPRINTF(("s%02x ", sta));
+ switch (sta) {
case MGSTATUS_ADDR_W_ACKR:
case MGSTATUS_MDATA_ACKR:
mgiic_write(sc, MGDATA, buf[i]);
- printf("w%02x ", buf[i]);
+ DPRINTF(("w%02x ", buf[i]));
i++;
mgiic_control(sc, 0, MGCONTROL_IFLG);
break;
case MGSTATUS_ADDR_W_NOACKR:
case MGSTATUS_MDATA_NOACKR:
mgiic_write(sc, MGDATA, buf[i]);
- printf("w%02x ", buf[i]);
+ DPRINTF(("w%02x ", buf[i]));
mgiic_control(sc, 0, MGCONTROL_IFLG);
break;
case MGSTATUS_BUSERR:
@@ -247,42 +317,44 @@ top:
goto bail;
}
}
- printf("OK ");
+ DPRINTF(("OK "));
err = 0;
bail:
if (err)
- printf("BAIL STP s%02x\n", mgiic_read(sc, MGSTATUS));
+ DPRINTF(("BAIL STP s%02x\n", mgiic_read(sc, MGSTATUS)));
mgiic_control(sc, MGCONTROL_STP, MGCONTROL_IFLG);
- while (mgiic_read(sc, MGSTATUS) != MGSTATUS_IDLE)
- ;
- printf("s%02x\n", mgiic_read(sc, MGSTATUS));
+ sta = mgiic_read(sc, MGSTATUS);
+ while (sta != MGSTATUS_IDLE) /* XXX timeout & reset hw ?*/
+ sta = mgiic_read(sc, MGSTATUS);
return (err);
}
int
mgiic_recv(struct mgiic_softc *sc, u_int8_t addr, u_int8_t *buf, size_t len)
{
- int err = 1, i = 0;
+ int err = 1, i = 0, sta = 0;
- printf("recv s%02x ", mgiic_read(sc, MGSTATUS));
+ DPRINTF(("recv s%02x ", mgiic_read(sc, MGSTATUS)));
mgiic_control(sc, MGCONTROL_STA, MGCONTROL_IFLG);
if (mgiic_poll(sc))
goto bail;
- printf("s%02x ", mgiic_read(sc, MGSTATUS));
- if (mgiic_read(sc, MGSTATUS) != MGSTATUS_STARTSENT)
+ sta = mgiic_read(sc, MGSTATUS);
+ DPRINTF(("s%02x ", sta));
+ if (sta != MGSTATUS_STARTSENT)
goto bail;
re_address:
mgiic_write(sc, MGDATA, (addr << 1) | 0x01);
- printf("a%02x ", (addr << 1) | 0x01);
+ DPRINTF(("a%02x ", (addr << 1) | 0x01));
mgiic_control(sc, 0, MGCONTROL_IFLG);
while (i < len) {
if (mgiic_poll(sc))
goto bail;
- printf("s%02x ", mgiic_read(sc, MGSTATUS));
- switch (mgiic_read(sc, MGSTATUS)) {
+ sta = mgiic_read(sc, MGSTATUS);
+ DPRINTF(("s%02x ", sta));
+ switch (sta) {
case MGSTATUS_ADDR_R_ACKR:
if (len - i > 1)
mgiic_control(sc, MGCONTROL_AAK,
MGCONTROL_IFLG);
@@ -296,7 +368,7 @@ re_address:
goto re_address;
case MGSTATUS_MDATA_ACKT:
buf[i] = mgiic_read(sc, MGDATA);
- printf("r%02x ", buf[i]);
+ DPRINTF(("r%02x ", buf[i]));
i++;
if (len - i > 1)
mgiic_control(sc, MGCONTROL_AAK,
MGCONTROL_IFLG);
@@ -305,33 +377,35 @@ re_address:
break;
case MGSTATUS_MDATA_NOACKT:
buf[i] = mgiic_read(sc, MGDATA);
- printf("r%02x ", buf[i]);
+ DPRINTF(("r%02x ", buf[i]));
i++;
if (len == i) {
- printf("DONE ");
+ DPRINTF(("DONE "));
err = 0;
goto bail;
}
- printf("SHORT ");
+ DPRINTF(("SHORT "));
goto bail;
break;
default:
- printf("BAD");
+ DPRINTF(("BAD"));
goto bail;
}
}
- printf("OK ");
+ DPRINTF(("OK "));
err = 0;
bail:
if (err)
- printf("BAIL STP s%02x\n", mgiic_read(sc, MGSTATUS));
+ DPRINTF(("BAIL STP s%02x\n", mgiic_read(sc, MGSTATUS)));
mgiic_control(sc, MGCONTROL_STP, MGCONTROL_IFLG | MGCONTROL_AAK);
- while (mgiic_read(sc, MGSTATUS) != MGSTATUS_IDLE)
- ;
- printf("s%02x\n", mgiic_read(sc, MGSTATUS));
+ sta = mgiic_read(sc, MGSTATUS);
+ while (sta != MGSTATUS_IDLE) /* XXX */
+ sta = mgiic_read(sc, MGSTATUS);
+
return (err);
}
+#ifdef __sparc64__
volatile u_int8_t
mgiic_read(struct mgiic_softc *sc, bus_size_t r)
{
@@ -349,6 +423,39 @@ mgiic_write(struct mgiic_softc *sc, bus_size_t r, u_int8_t
v)
bus_space_barrier(sc->sc_bt, sc->sc_regh, r, 8,
BUS_SPACE_BARRIER_WRITE);
}
+#else
+int
+mgiic_intr(void *arg)
+{
+ struct mgiic_softc *sc = arg;
+ u_int val;
+
+ val = mgiic_read(sc, MGCONTROL);
+ if (val & MGCONTROL_IFLG) {
+ mgiic_write(sc, MG_CONTROL, val & ~MGCONTROL_IEN);
+ wakeup(&sc->sc_dev);
+ return 1;
+ }
+ return 0;
+}
+
+volatile u_int8_t
+_mgiic_read(struct mgiic_softc *sc, bus_size_t r)
+{
+ uint32_t val = bus_space_read_4(sc->sc_bt, sc->sc_regh, r);
+ delay(MGRDWRDELAY);
+ return val & 0xff;
+}
+
+volatile void
+_mgiic_write(struct mgiic_softc *sc, bus_size_t r, u_int8_t v)
+{
+ uint32_t val = v;
+
+ bus_space_write_4(sc->sc_bt, sc->sc_regh, r, val);
+ delay(MGRDWRDELAY);
+}
+#endif
volatile void
mgiic_control(struct mgiic_softc *sc, u_int8_t on, u_int8_t off)