Import the exynos work into tree. This is from Bitrig. Discussed with and OK jsg...
authorbmercer <bmercer@openbsd.org>
Mon, 26 Jan 2015 02:48:24 +0000 (02:48 +0000)
committerbmercer <bmercer@openbsd.org>
Mon, 26 Jan 2015 02:48:24 +0000 (02:48 +0000)
28 files changed:
sys/arch/armv7/exynos/crosec.c [new file with mode: 0644]
sys/arch/armv7/exynos/crosec_kbd.c [new file with mode: 0644]
sys/arch/armv7/exynos/crosecvar.h [new file with mode: 0644]
sys/arch/armv7/exynos/ec_commands.h [new file with mode: 0644]
sys/arch/armv7/exynos/exclock.c [new file with mode: 0644]
sys/arch/armv7/exynos/exclockvar.h [new file with mode: 0644]
sys/arch/armv7/exynos/exdisplay.c [new file with mode: 0644]
sys/arch/armv7/exynos/exdisplayvar.h [new file with mode: 0644]
sys/arch/armv7/exynos/exdog.c [new file with mode: 0644]
sys/arch/armv7/exynos/exehci.c [new file with mode: 0644]
sys/arch/armv7/exynos/exesdhc.c [new file with mode: 0644]
sys/arch/armv7/exynos/exgpio.c [new file with mode: 0644]
sys/arch/armv7/exynos/exgpiovar.h [new file with mode: 0644]
sys/arch/armv7/exynos/exiic.c [new file with mode: 0644]
sys/arch/armv7/exynos/exiicvar.h [new file with mode: 0644]
sys/arch/armv7/exynos/exmct.c [new file with mode: 0644]
sys/arch/armv7/exynos/expower.c [new file with mode: 0644]
sys/arch/armv7/exynos/expowervar.h [new file with mode: 0644]
sys/arch/armv7/exynos/exsysreg.c [new file with mode: 0644]
sys/arch/armv7/exynos/exsysregvar.h [new file with mode: 0644]
sys/arch/armv7/exynos/exuart.c [new file with mode: 0644]
sys/arch/armv7/exynos/exuartreg.h [new file with mode: 0644]
sys/arch/armv7/exynos/exuartvar.h [new file with mode: 0644]
sys/arch/armv7/exynos/exynos.c [new file with mode: 0644]
sys/arch/armv7/exynos/exynos5.c [new file with mode: 0644]
sys/arch/armv7/exynos/exynos_machdep.c [new file with mode: 0644]
sys/arch/armv7/exynos/files.exynos [new file with mode: 0644]
sys/arch/armv7/exynos/tps65090.c [new file with mode: 0644]

diff --git a/sys/arch/armv7/exynos/crosec.c b/sys/arch/armv7/exynos/crosec.c
new file mode 100644 (file)
index 0000000..21178b4
--- /dev/null
@@ -0,0 +1,274 @@
+/* $OpenBSD: crosec.c,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
+/*
+ * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/sensors.h>
+#include <sys/malloc.h>
+
+#include <armv7/exynos/crosecvar.h>
+
+#ifdef DEBUG
+#define DPRINTF(x) printf x
+#else
+#define DPRINTF(x)
+#endif
+
+int    cros_ec_match(struct device *, void *, void *);
+void   cros_ec_attach(struct device *, struct device *, void *);
+
+int    cros_ec_send_command(struct cros_ec_softc *, uint8_t,
+               int, const void *, int, uint8_t **, int);
+int    cros_ec_command(struct cros_ec_softc *, uint8_t,
+               int, const void *, int, void *, int);
+int    cros_ec_command_inptr(struct cros_ec_softc *, uint8_t,
+               int, const void *, int, uint8_t **, int);
+int    cros_ec_i2c_command(struct cros_ec_softc *, uint8_t,
+               int, const uint8_t *, int, uint8_t **, int);
+int    cros_ec_calc_checksum(const uint8_t *, int);
+
+struct cfattach crosec_ca = {
+       sizeof(struct cros_ec_softc), cros_ec_match, cros_ec_attach
+};
+
+struct cfdriver crosec_cd = {
+       NULL, "crosec", DV_DULL
+};
+
+int
+cros_ec_match(struct device *parent, void *match, void *aux)
+{
+       struct i2c_attach_args *ia = aux;
+
+       if (strcmp(ia->ia_name, "crosec") == 0)
+               return 1;
+       return 0;
+}
+
+void
+cros_ec_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct cros_ec_softc *sc = (struct cros_ec_softc *)self;
+       struct i2c_attach_args *ia = aux;
+
+       sc->sc_tag = ia->ia_tag;
+       sc->sc_addr = ia->ia_addr;
+
+       printf("\n");
+
+       if (cros_ec_check_version(sc)) {
+               printf("%s: could not initialize ChromeOS EC\n", __func__);
+               return;
+       }
+
+       if (cros_ec_init_keyboard(sc)) {
+               printf("%s: could not initialize keyboard\n", __func__);
+               return;
+       }
+}
+
+int
+cros_ec_check_version(struct cros_ec_softc *sc)
+{
+       struct ec_params_hello req;
+       struct ec_response_hello *resp;
+
+       sc->cmd_version_is_supported = 1;
+       if (cros_ec_command_inptr(sc, EC_CMD_HELLO, 0, &req, sizeof(req),
+                               (uint8_t **)&resp, sizeof(*resp)) > 0) {
+               /* new version supported */
+               sc->cmd_version_is_supported = 1;
+       } else {
+               printf("%s: old EC interface not supported\n", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+int
+cros_ec_i2c_command(struct cros_ec_softc *sc, uint8_t cmd, int cmd_version,
+               const uint8_t *out, int out_len, uint8_t **in, int in_len)
+{
+       int out_bytes, in_bytes, ret;
+       uint8_t *ptr = sc->out;
+       uint8_t *inptr = sc->in;
+
+       inptr += sizeof(uint64_t); /* returned data should be 64-bit aligned */
+       if (!sc->cmd_version_is_supported) {
+               /* old-style */
+               *ptr++ = cmd;
+               out_bytes = out_len + 1;
+               in_bytes = in_len + 2;
+               inptr--; /* status byte */
+       } else {
+               /* new-style */
+               *ptr++ = EC_CMD_VERSION0 + cmd_version;
+               *ptr++ = cmd;
+               *ptr++ = out_len;
+               out_bytes = out_len + 4;
+               in_bytes = in_len + 3;
+               inptr -= 2; /* status byte, length */
+       }
+       memcpy(ptr, out, out_len);
+       ptr += out_len;
+
+       if (sc->cmd_version_is_supported)
+               *ptr++ = (uint8_t)
+                        cros_ec_calc_checksum(sc->out, out_len + 3);
+
+       iic_acquire_bus(sc->sc_tag, 0);
+       ret = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
+           sc->sc_addr, NULL, 0, &sc->out, out_bytes, 0);
+       if (ret) {
+               DPRINTF(("%s: I2C write failed\n", __func__));
+               iic_release_bus(sc->sc_tag, 0);
+               return -1;
+       }
+
+       ret = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+           sc->sc_addr, NULL, 0, inptr, in_bytes, 0);
+       if (ret) {
+               DPRINTF(("%s: I2C read failed\n", __func__));
+               iic_release_bus(sc->sc_tag, 0);
+               return -1;
+       }
+
+       iic_release_bus(sc->sc_tag, 0);
+
+       if (*inptr != EC_RES_SUCCESS) {
+               DPRINTF(("%s: bad result\n", __func__));
+               return -(int)*inptr;
+       }
+
+       if (sc->cmd_version_is_supported) {
+               int len, csum;
+
+               len = inptr[1];
+               if (len > sizeof(sc->in)) {
+                       DPRINTF(("%s: Received length too large\n", __func__));
+                       return -1;
+               }
+               csum = cros_ec_calc_checksum(inptr, 2 + len);
+               if (csum != inptr[2 + len]) {
+                       DPRINTF(("%s: Invalid checksum\n", __func__));
+                       return -1;
+               }
+               in_len = min(in_len, len);
+       }
+
+       *in = sc->in + sizeof(uint64_t);
+
+       return in_len;
+}
+
+int
+cros_ec_send_command(struct cros_ec_softc *sc, uint8_t cmd, int cmd_version,
+               const void *out, int out_len, uint8_t **in, int in_len)
+{
+       return cros_ec_i2c_command(sc, cmd, cmd_version,
+                               (const uint8_t *)out, out_len, in, in_len);
+}
+
+int
+cros_ec_command(struct cros_ec_softc *sc, uint8_t cmd,
+               int cmd_version, const void *out, int out_len,
+               void *in, int in_len) {
+       uint8_t *in_buffer;
+       int len;
+
+       len = cros_ec_command_inptr(sc, cmd, cmd_version, out, out_len,
+                       &in_buffer, in_len);
+
+       if (len > 0) {
+               if (in && in_buffer) {
+                       len = min(in_len, len);
+                       memmove(in, in_buffer, len);
+               }
+       }
+       return len;
+}
+
+int
+cros_ec_command_inptr(struct cros_ec_softc *sc, uint8_t cmd,
+               int cmd_version, const void *out, int out_len,
+               uint8_t **inp, int in_len) {
+       uint8_t *in;
+       int len;
+
+       len = cros_ec_send_command(sc, cmd, cmd_version,
+                       (const uint8_t *)out, out_len, &in, in_len);
+
+       /* Wait for the command to complete. */
+       if (len == -EC_RES_IN_PROGRESS) {
+               struct ec_response_get_comms_status *resp;
+
+               do {
+                       int ret;
+
+                       delay(50000);
+                       cros_ec_send_command(sc, EC_CMD_GET_COMMS_STATUS, 0,
+                                       NULL, 0,
+                                       (uint8_t **)&resp, sizeof(*resp));
+                       if (ret < 0)
+                               return ret;
+
+                       //timeout CROS_EC_CMD_TIMEOUT_MS
+                       //return -EC_RES_TIMEOUT
+               } while (resp->flags & EC_COMMS_STATUS_PROCESSING);
+
+               /* Let's get the response. */
+               len = cros_ec_send_command(sc, EC_CMD_RESEND_RESPONSE, 0,
+                               out, out_len, &in, in_len);
+       }
+
+       if (inp != NULL)
+               *inp = in;
+
+       return len;
+}
+
+int
+cros_ec_calc_checksum(const uint8_t *data, int size)
+{
+       int csum, i;
+
+       for (i = csum = 0; i < size; i++)
+               csum += data[i];
+       return csum & 0xff;
+}
+
+int
+cros_ec_scan_keyboard(struct cros_ec_softc *sc, uint8_t *scan, int len)
+{
+       if (cros_ec_command(sc, EC_CMD_CROS_EC_STATE, 0, NULL, 0, scan,
+                       len) < len)
+               return -1;
+
+       return 0;
+}
+
+int
+cros_ec_info(struct cros_ec_softc *sc, struct ec_response_cros_ec_info *info)
+{
+       if (cros_ec_command(sc, EC_CMD_CROS_EC_INFO, 0, NULL, 0, info,
+                               sizeof(*info)) < sizeof(*info))
+               return -1;
+
+       return 0;
+}
diff --git a/sys/arch/armv7/exynos/crosec_kbd.c b/sys/arch/armv7/exynos/crosec_kbd.c
new file mode 100644 (file)
index 0000000..cc8e015
--- /dev/null
@@ -0,0 +1,249 @@
+/* $OpenBSD: crosec_kbd.c,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
+/*
+ * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/sensors.h>
+#include <sys/malloc.h>
+
+#include <armv7/exynos/crosecvar.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wskbdvar.h>
+#include <dev/wscons/wsksymdef.h>
+#include <dev/wscons/wsksymvar.h>
+
+int cros_ec_get_keystate(struct cros_ec_softc *);
+
+int cros_ec_keyboard_enable(void *, int);
+void cros_ec_keyboard_set_leds(void *, int);
+int cros_ec_keyboard_ioctl(void *, u_long, caddr_t, int, struct proc *);
+
+struct wskbd_accessops cros_ec_keyboard_accessops = {
+       cros_ec_keyboard_enable,
+       cros_ec_keyboard_set_leds,
+       cros_ec_keyboard_ioctl,
+};
+
+void cros_ec_keyboard_cngetc(void *, u_int *, int *);
+void cros_ec_keyboard_cnpollc(void *, int);
+
+struct wskbd_consops cros_ec_keyboard_consops = {
+       cros_ec_keyboard_cngetc,
+       cros_ec_keyboard_cnpollc,
+};
+
+
+/* XXX: assumes 8 rows, 13 cols, FDT */
+#define KC(n) KS_KEYCODE(n)
+static const keysym_t cros_ec_keyboard_keydesc_us[] = {
+       KC(1),  KS_Caps_Lock,
+       KC(3),  KS_b,
+       KC(6),  KS_n,
+       KC(10), KS_Alt_R,
+       KC(14), KS_Escape,
+       KC(16), KS_g,
+       KC(19), KS_h,
+       KC(24), KS_BackSpace,
+       KC(26), KS_Control_L,
+       KC(27), KS_Tab,
+       KC(29), KS_t,
+       KC(32), KS_y,
+       KC(42), KS_5,
+       KC(45), KS_6,
+       KC(52), KS_Control_R,
+       KC(53), KS_a,
+       KC(54), KS_d,
+       KC(55), KS_f,
+       KC(56), KS_s,
+       KC(57), KS_k,
+       KC(58), KS_j,
+       KC(61), KS_l,
+       KC(63), KS_Return,
+       KC(66), KS_z,
+       KC(67), KS_c,
+       KC(68), KS_v,
+       KC(69), KS_x,
+       KC(70), KS_comma,
+       KC(71), KS_m,
+       KC(72), KS_Shift_L,
+       KC(74), KS_period,
+       KC(76), KS_space,
+       KC(79), KS_1,
+       KC(80), KS_3,
+       KC(81), KS_4,
+       KC(82), KS_2,
+       KC(83), KS_8,
+       KC(84), KS_7,
+       KC(86), KS_0,
+       KC(87), KS_9,
+       KC(88), KS_Alt_L,
+       KC(92), KS_q,
+       KC(93), KS_e,
+       KC(94), KS_r,
+       KC(95), KS_w,
+       KC(96), KS_i,
+       KC(97), KS_u,
+       KC(98), KS_Shift_R,
+       KC(99), KS_p,
+       KC(100),        KS_o,
+};
+
+#define KBD_MAP(name, base, map) \
+       { name, base, sizeof(map)/sizeof(keysym_t), map }
+static const struct wscons_keydesc cros_ec_keyboard_keydesctab[] = {
+       KBD_MAP(KB_US,                  0,      cros_ec_keyboard_keydesc_us),
+       {0, 0, 0, 0}
+};
+struct wskbd_mapdata cros_ec_keyboard_keymapdata = {
+       cros_ec_keyboard_keydesctab,
+       KB_US,
+};
+
+int
+cros_ec_init_keyboard(struct cros_ec_softc *sc)
+{
+       struct ec_response_cros_ec_info info;
+       struct wskbddev_attach_args a;
+
+       if (cros_ec_info(sc, &info)) {
+               printf("%s: could not read KBC info\n", __func__);
+               return (-1);
+       }
+
+       sc->keyboard.rows = info.rows;
+       sc->keyboard.cols = info.cols;
+       sc->keyboard.switches = info.switches;
+       sc->keyboard.state = (uint8_t *)malloc(info.rows*info.cols,
+                       M_DEVBUF, M_WAITOK|M_ZERO);
+       if (sc->keyboard.state == NULL)
+               panic("%s: no memory available for keyboard states", __func__);
+
+       /* XXX: ghosting */
+
+#if 0
+       while (sc->keyboard.state != NULL) {
+               cros_ec_get_keystate(sc);
+               delay(100000);
+       }
+#endif
+
+       wskbd_cnattach(&cros_ec_keyboard_consops, sc, &cros_ec_keyboard_keymapdata);
+       a.console = 1;
+
+       a.keymap = &cros_ec_keyboard_keymapdata;
+       a.accessops = &cros_ec_keyboard_accessops;
+       a.accesscookie = sc;
+
+       sc->keyboard.wskbddev = config_found((void *)sc, &a, wskbddevprint);
+
+       return 0;
+}
+
+int
+cros_ec_get_keystate(struct cros_ec_softc *sc)
+{
+       int col, row;
+       uint8_t state[sc->keyboard.cols];
+       cros_ec_scan_keyboard(sc, state, sc->keyboard.cols);
+       for (col = 0; col < sc->keyboard.cols; col++) {
+               for (row = 0; row < sc->keyboard.rows; row++) {
+                       int off = row*sc->keyboard.cols;
+                       int pressed = !!(state[col] & (1 << row));
+                       if (pressed && !sc->keyboard.state[off+col]) {
+                               //printf("row %d col %d id %d pressed\n", row, col, off+col);
+                               sc->keyboard.state[off+col] = 1;
+                               if (sc->keyboard.polling)
+                                       return off+col;
+                               wskbd_input(sc->keyboard.wskbddev, WSCONS_EVENT_KEY_DOWN, off+col);
+                       } else if (!pressed && sc->keyboard.state[off+col]) {
+                               //printf("row %d col %d id %d released\n", row, col, off+col);
+                               sc->keyboard.state[off+col] = 0;
+                               if (sc->keyboard.polling)
+                                       return off+col;
+                               wskbd_input(sc->keyboard.wskbddev, WSCONS_EVENT_KEY_UP, off+col);
+                       } else if (sc->keyboard.state[off+col]) {
+                               //printf("row %d col %d id %d repeated\n", row, col, off+col);
+                               if (sc->keyboard.polling)
+                                       return off+col;
+                       }
+               }
+       }
+       return (-1);
+}
+
+void
+cros_ec_keyboard_cngetc(void *v, u_int *type, int *data)
+{
+       struct cros_ec_softc *sc = v;
+       int key;
+
+       sc->keyboard.polling = 1;
+       while ((key = cros_ec_get_keystate(sc)) == -1) {
+               delay(10000);
+       }
+       sc->keyboard.polling = 0;
+
+       *data = key;
+       *type = sc->keyboard.state[key] ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
+}
+
+void
+cros_ec_keyboard_cnpollc(void *v, int on)
+{
+}
+
+int
+cros_ec_keyboard_enable(void *v, int on)
+{
+       return 0;
+}
+
+void
+cros_ec_keyboard_set_leds(void *v, int on)
+{
+}
+
+int
+cros_ec_keyboard_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+#ifdef WSDISPLAY_COMPAT_RAWKBD
+       struct cros_ec_softc *sc = v;
+#endif
+
+       switch (cmd) {
+
+       case WSKBDIO_GTYPE:
+               *(int *)data = WSKBD_TYPE_ZAURUS;
+               return 0;
+       case WSKBDIO_SETLEDS:
+               return 0;
+       case WSKBDIO_GETLEDS:
+               *(int *)data = 0;
+               return 0;
+#ifdef WSDISPLAY_COMPAT_RAWKBD
+       case WSKBDIO_SETMODE:
+               sc->rawkbd = *(int *)data == WSKBD_RAW;
+               return (0);
+#endif
+
+       }
+       /* kbdioctl(...); */
+
+       return -1;
+}
diff --git a/sys/arch/armv7/exynos/crosecvar.h b/sys/arch/armv7/exynos/crosecvar.h
new file mode 100644 (file)
index 0000000..1f869c3
--- /dev/null
@@ -0,0 +1,61 @@
+/* $OpenBSD: crosecvar.h,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
+/*
+ * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef CROSECVAR_H
+#define CROSECVAR_H
+
+#include <dev/i2c/i2cvar.h>
+#include <armv7/exynos/ec_commands.h>
+
+/* message sizes */
+#define MSG_HEADER             0xec
+#define MSG_HEADER_BYTES       3
+#define MSG_TRAILER_BYTES      2
+#define MSG_PROTO_BYTES                (MSG_HEADER_BYTES + MSG_TRAILER_BYTES)
+#define MSG_BYTES              (EC_HOST_PARAM_SIZE + MSG_PROTO_BYTES)
+#define MSG_BYTES_ALIGNED      ((MSG_BYTES+8) & ~8)
+
+#define min(a,b)       (((a)<(b))?(a):(b))
+
+struct cros_ec_softc {
+       struct device sc_dev;
+       i2c_tag_t sc_tag;
+       i2c_addr_t sc_addr;
+
+       int cmd_version_is_supported;
+       struct {
+               int rows;
+               int cols;
+               int switches;
+               uint8_t *state;
+
+               /* wskbd bits */
+               struct device *wskbddev;
+               int rawkbd;
+               int polling;
+       } keyboard;
+       uint8_t in[MSG_BYTES_ALIGNED];
+       uint8_t out[MSG_BYTES_ALIGNED];
+};
+
+int    cros_ec_check_version(struct cros_ec_softc *);
+int    cros_ec_scan_keyboard(struct cros_ec_softc *, uint8_t *, int);
+int    cros_ec_info(struct cros_ec_softc *, struct ec_response_cros_ec_info *);
+
+int    cros_ec_init_keyboard(struct cros_ec_softc *);
+
+#endif /* !CROSECVAR_H */
diff --git a/sys/arch/armv7/exynos/ec_commands.h b/sys/arch/armv7/exynos/ec_commands.h
new file mode 100644 (file)
index 0000000..8dc2df0
--- /dev/null
@@ -0,0 +1,1500 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Host communication command constants for Chrome EC */
+
+#ifndef __CROS_EC_COMMANDS_H
+#define __CROS_EC_COMMANDS_H
+
+/*
+ * Protocol overview
+ *
+ * request:  CMD [ P0 P1 P2 ... Pn S ]
+ * response: ERR [ P0 P1 P2 ... Pn S ]
+ *
+ * where the bytes are defined as follow :
+ *      - CMD is the command code. (defined by EC_CMD_ constants)
+ *      - ERR is the error code. (defined by EC_RES_ constants)
+ *      - Px is the optional payload.
+ *        it is not sent if the error code is not success.
+ *        (defined by ec_params_ and ec_response_ structures)
+ *      - S is the checksum which is the sum of all payload bytes.
+ *
+ * On LPC, CMD and ERR are sent/received at EC_LPC_ADDR_KERNEL|USER_CMD
+ * and the payloads are sent/received at EC_LPC_ADDR_KERNEL|USER_PARAM.
+ * On I2C, all bytes are sent serially in the same message.
+ */
+
+/* Current version of this protocol */
+#define EC_PROTO_VERSION          0x00000002
+
+/* Command version mask */
+#define EC_VER_MASK(version) (1UL << (version))
+
+/* I/O addresses for ACPI commands */
+#define EC_LPC_ADDR_ACPI_DATA  0x62
+#define EC_LPC_ADDR_ACPI_CMD   0x66
+
+/* I/O addresses for host command */
+#define EC_LPC_ADDR_HOST_DATA  0x200
+#define EC_LPC_ADDR_HOST_CMD   0x204
+
+/* I/O addresses for host command args and params */
+#define EC_LPC_ADDR_HOST_ARGS  0x800
+#define EC_LPC_ADDR_HOST_PARAM 0x804
+#define EC_HOST_PARAM_SIZE     0x0fc  /* Size of param area in bytes */
+
+/* EC command register bit functions */
+#define EC_LPC_CMDR_DATA       (1 << 0)  /* Data ready for host to read */
+#define EC_LPC_CMDR_PENDING    (1 << 1)  /* Write pending to EC */
+#define EC_LPC_CMDR_BUSY       (1 << 2)  /* EC is busy processing a command */
+#define EC_LPC_CMDR_CMD                (1 << 3)  /* Last host write was a command */
+#define EC_LPC_CMDR_ACPI_BRST  (1 << 4)  /* Burst mode (not used) */
+#define EC_LPC_CMDR_SCI                (1 << 5)  /* SCI event is pending */
+#define EC_LPC_CMDR_SMI                (1 << 6)  /* SMI event is pending */
+
+#define EC_LPC_ADDR_MEMMAP       0x900
+#define EC_MEMMAP_SIZE         255 /* ACPI IO buffer max is 255 bytes */
+#define EC_MEMMAP_TEXT_MAX     8   /* Size of a string in the memory map */
+
+/* The offset address of each type of data in mapped memory. */
+#define EC_MEMMAP_TEMP_SENSOR      0x00 /* Temp sensors */
+#define EC_MEMMAP_FAN              0x10 /* Fan speeds */
+#define EC_MEMMAP_TEMP_SENSOR_B    0x18 /* Temp sensors (second set) */
+#define EC_MEMMAP_ID               0x20 /* 'E' 'C' */
+#define EC_MEMMAP_ID_VERSION       0x22 /* Version of data in 0x20 - 0x2f */
+#define EC_MEMMAP_THERMAL_VERSION  0x23 /* Version of data in 0x00 - 0x1f */
+#define EC_MEMMAP_BATTERY_VERSION  0x24 /* Version of data in 0x40 - 0x7f */
+#define EC_MEMMAP_SWITCHES_VERSION 0x25 /* Version of data in 0x30 - 0x33 */
+#define EC_MEMMAP_EVENTS_VERSION   0x26 /* Version of data in 0x34 - 0x3f */
+#define EC_MEMMAP_HOST_CMD_FLAGS   0x27 /* Host command interface flags */
+#define EC_MEMMAP_SWITCHES         0x30
+#define EC_MEMMAP_HOST_EVENTS      0x34
+#define EC_MEMMAP_BATT_VOLT        0x40 /* Battery Present Voltage */
+#define EC_MEMMAP_BATT_RATE        0x44 /* Battery Present Rate */
+#define EC_MEMMAP_BATT_CAP         0x48 /* Battery Remaining Capacity */
+#define EC_MEMMAP_BATT_FLAG        0x4c /* Battery State, defined below */
+#define EC_MEMMAP_BATT_DCAP        0x50 /* Battery Design Capacity */
+#define EC_MEMMAP_BATT_DVLT        0x54 /* Battery Design Voltage */
+#define EC_MEMMAP_BATT_LFCC        0x58 /* Battery Last Full Charge Capacity */
+#define EC_MEMMAP_BATT_CCNT        0x5c /* Battery Cycle Count */
+#define EC_MEMMAP_BATT_MFGR        0x60 /* Battery Manufacturer String */
+#define EC_MEMMAP_BATT_MODEL       0x68 /* Battery Model Number String */
+#define EC_MEMMAP_BATT_SERIAL      0x70 /* Battery Serial Number String */
+#define EC_MEMMAP_BATT_TYPE        0x78 /* Battery Type String */
+
+/* Number of temp sensors at EC_MEMMAP_TEMP_SENSOR */
+#define EC_TEMP_SENSOR_ENTRIES     16
+/*
+ * Number of temp sensors at EC_MEMMAP_TEMP_SENSOR_B.
+ *
+ * Valid only if EC_MEMMAP_THERMAL_VERSION returns >= 2.
+ */
+#define EC_TEMP_SENSOR_B_ENTRIES      8
+#define EC_TEMP_SENSOR_NOT_PRESENT    0xff
+#define EC_TEMP_SENSOR_ERROR          0xfe
+#define EC_TEMP_SENSOR_NOT_POWERED    0xfd
+#define EC_TEMP_SENSOR_NOT_CALIBRATED 0xfc
+/*
+ * The offset of temperature value stored in mapped memory.  This allows
+ * reporting a temperature range of 200K to 454K = -73C to 181C.
+ */
+#define EC_TEMP_SENSOR_OFFSET      200
+
+#define EC_FAN_SPEED_ENTRIES       4       /* Number of fans at EC_MEMMAP_FAN */
+#define EC_FAN_SPEED_NOT_PRESENT   0xffff  /* Entry not present */
+#define EC_FAN_SPEED_STALLED       0xfffe  /* Fan stalled */
+
+/* Battery bit flags at EC_MEMMAP_BATT_FLAG. */
+#define EC_BATT_FLAG_AC_PRESENT   0x01
+#define EC_BATT_FLAG_BATT_PRESENT 0x02
+#define EC_BATT_FLAG_DISCHARGING  0x04
+#define EC_BATT_FLAG_CHARGING     0x08
+#define EC_BATT_FLAG_LEVEL_CRITICAL 0x10
+
+/* Switch flags at EC_MEMMAP_SWITCHES */
+#define EC_SWITCH_LID_OPEN               0x01
+#define EC_SWITCH_POWER_BUTTON_PRESSED   0x02
+#define EC_SWITCH_WRITE_PROTECT_DISABLED 0x04
+/* Was recovery requested via keyboard; now unused. */
+#define EC_SWITCH_IGNORE1               0x08
+/* Recovery requested via dedicated signal (from servo board) */
+#define EC_SWITCH_DEDICATED_RECOVERY     0x10
+/* Was fake developer mode switch; now unused.  Remove in next refactor. */
+#define EC_SWITCH_IGNORE0                0x20
+
+/* Host command interface flags */
+/* Host command interface supports LPC args (LPC interface only) */
+#define EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED  0x01
+
+/* Wireless switch flags */
+#define EC_WIRELESS_SWITCH_WLAN      0x01
+#define EC_WIRELESS_SWITCH_BLUETOOTH 0x02
+
+/*
+ * This header file is used in coreboot both in C and ACPI code.  The ACPI code
+ * is pre-processed to handle constants but the ASL compiler is unable to
+ * handle actual C code so keep it separate.
+ */
+#ifndef __ACPI__
+
+/*
+ * Define __packed if someone hasn't beat us to it.  Linux kernel style
+ * checking prefers __packed over __attribute__((packed)).
+ */
+#ifndef __packed
+#define __packed __attribute__((packed))
+#endif
+
+/* LPC command status byte masks */
+/* EC has written a byte in the data register and host hasn't read it yet */
+#define EC_LPC_STATUS_TO_HOST     0x01
+/* Host has written a command/data byte and the EC hasn't read it yet */
+#define EC_LPC_STATUS_FROM_HOST   0x02
+/* EC is processing a command */
+#define EC_LPC_STATUS_PROCESSING  0x04
+/* Last write to EC was a command, not data */
+#define EC_LPC_STATUS_LAST_CMD    0x08
+/* EC is in burst mode.  Unsupported by Chrome EC, so this bit is never set */
+#define EC_LPC_STATUS_BURST_MODE  0x10
+/* SCI event is pending (requesting SCI query) */
+#define EC_LPC_STATUS_SCI_PENDING 0x20
+/* SMI event is pending (requesting SMI query) */
+#define EC_LPC_STATUS_SMI_PENDING 0x40
+/* (reserved) */
+#define EC_LPC_STATUS_RESERVED    0x80
+
+/*
+ * EC is busy.  This covers both the EC processing a command, and the host has
+ * written a new command but the EC hasn't picked it up yet.
+ */
+#define EC_LPC_STATUS_BUSY_MASK \
+       (EC_LPC_STATUS_FROM_HOST | EC_LPC_STATUS_PROCESSING)
+
+/* Host command response codes */
+enum ec_status {
+       EC_RES_SUCCESS = 0,
+       EC_RES_INVALID_COMMAND = 1,
+       EC_RES_ERROR = 2,
+       EC_RES_INVALID_PARAM = 3,
+       EC_RES_ACCESS_DENIED = 4,
+       EC_RES_INVALID_RESPONSE = 5,
+       EC_RES_INVALID_VERSION = 6,
+       EC_RES_INVALID_CHECKSUM = 7,
+       EC_RES_IN_PROGRESS = 8,         /* Accepted, command in progress */
+       EC_RES_UNAVAILABLE = 9,         /* No response available */
+       EC_RES_TIMEOUT = 10,            /* We got a timeout */
+       EC_RES_OVERFLOW = 11,           /* Table / data overflow */
+};
+
+/*
+ * Host event codes.  Note these are 1-based, not 0-based, because ACPI query
+ * EC command uses code 0 to mean "no event pending".  We explicitly specify
+ * each value in the enum listing so they won't change if we delete/insert an
+ * item or rearrange the list (it needs to be stable across platforms, not
+ * just within a single compiled instance).
+ */
+enum host_event_code {
+       EC_HOST_EVENT_LID_CLOSED = 1,
+       EC_HOST_EVENT_LID_OPEN = 2,
+       EC_HOST_EVENT_POWER_BUTTON = 3,
+       EC_HOST_EVENT_AC_CONNECTED = 4,
+       EC_HOST_EVENT_AC_DISCONNECTED = 5,
+       EC_HOST_EVENT_BATTERY_LOW = 6,
+       EC_HOST_EVENT_BATTERY_CRITICAL = 7,
+       EC_HOST_EVENT_BATTERY = 8,
+       EC_HOST_EVENT_THERMAL_THRESHOLD = 9,
+       EC_HOST_EVENT_THERMAL_OVERLOAD = 10,
+       EC_HOST_EVENT_THERMAL = 11,
+       EC_HOST_EVENT_USB_CHARGER = 12,
+       EC_HOST_EVENT_KEY_PRESSED = 13,
+       /*
+        * EC has finished initializing the host interface.  The host can check
+        * for this event following sending a EC_CMD_REBOOT_EC command to
+        * determine when the EC is ready to accept subsequent commands.
+        */
+       EC_HOST_EVENT_INTERFACE_READY = 14,
+       /* Keyboard recovery combo has been pressed */
+       EC_HOST_EVENT_KEYBOARD_RECOVERY = 15,
+
+       /* Shutdown due to thermal overload */
+       EC_HOST_EVENT_THERMAL_SHUTDOWN = 16,
+       /* Shutdown due to battery level too low */
+       EC_HOST_EVENT_BATTERY_SHUTDOWN = 17,
+
+       /*
+        * The high bit of the event mask is not used as a host event code.  If
+        * it reads back as set, then the entire event mask should be
+        * considered invalid by the host.  This can happen when reading the
+        * raw event status via EC_MEMMAP_HOST_EVENTS but the LPC interface is
+        * not initialized on the EC, or improperly configured on the host.
+        */
+       EC_HOST_EVENT_INVALID = 32
+};
+/* Host event mask */
+#define EC_HOST_EVENT_MASK(event_code) (1UL << ((event_code) - 1))
+
+/* Arguments at EC_LPC_ADDR_HOST_ARGS */
+struct ec_lpc_host_args {
+       uint8_t flags;
+       uint8_t command_version;
+       uint8_t data_size;
+       /*
+        * Checksum; sum of command + flags + command_version + data_size +
+        * all params/response data bytes.
+        */
+       uint8_t checksum;
+} __packed;
+
+/* Flags for ec_lpc_host_args.flags */
+/*
+ * Args are from host.  Data area at EC_LPC_ADDR_HOST_PARAM contains command
+ * params.
+ *
+ * If EC gets a command and this flag is not set, this is an old-style command.
+ * Command version is 0 and params from host are at EC_LPC_ADDR_OLD_PARAM with
+ * unknown length.  EC must respond with an old-style response (that is,
+ * withouth setting EC_HOST_ARGS_FLAG_TO_HOST).
+ */
+#define EC_HOST_ARGS_FLAG_FROM_HOST 0x01
+/*
+ * Args are from EC.  Data area at EC_LPC_ADDR_HOST_PARAM contains response.
+ *
+ * If EC responds to a command and this flag is not set, this is an old-style
+ * response.  Command version is 0 and response data from EC is at
+ * EC_LPC_ADDR_OLD_PARAM with unknown length.
+ */
+#define EC_HOST_ARGS_FLAG_TO_HOST   0x02
+
+/*
+ * Notes on commands:
+ *
+ * Each command is an 8-byte command value.  Commands which take params or
+ * return response data specify structs for that data.  If no struct is
+ * specified, the command does not input or output data, respectively.
+ * Parameter/response length is implicit in the structs.  Some underlying
+ * communication protocols (I2C, SPI) may add length or checksum headers, but
+ * those are implementation-dependent and not defined here.
+ */
+
+/*****************************************************************************/
+/* General / test commands */
+
+/*
+ * Get protocol version, used to deal with non-backward compatible protocol
+ * changes.
+ */
+#define EC_CMD_PROTO_VERSION 0x00
+
+struct ec_response_proto_version {
+       uint32_t version;
+} __packed;
+
+/*
+ * Hello.  This is a simple command to test the EC is responsive to
+ * commands.
+ */
+#define EC_CMD_HELLO 0x01
+
+struct ec_params_hello {
+       uint32_t in_data;  /* Pass anything here */
+} __packed;
+
+struct ec_response_hello {
+       uint32_t out_data;  /* Output will be in_data + 0x01020304 */
+} __packed;
+
+/* Get version number */
+#define EC_CMD_GET_VERSION 0x02
+
+enum ec_current_image {
+       EC_IMAGE_UNKNOWN = 0,
+       EC_IMAGE_RO,
+       EC_IMAGE_RW
+};
+
+struct ec_response_get_version {
+       /* Null-terminated version strings for RO, RW */
+       char version_string_ro[32];
+       char version_string_rw[32];
+       char reserved[32];       /* Was previously RW-B string */
+       uint32_t current_image;  /* One of ec_current_image */
+} __packed;
+
+/* Read test */
+#define EC_CMD_READ_TEST 0x03
+
+struct ec_params_read_test {
+       uint32_t offset;   /* Starting value for read buffer */
+       uint32_t size;     /* Size to read in bytes */
+} __packed;
+
+struct ec_response_read_test {
+       uint32_t data[32];
+} __packed;
+
+/*
+ * Get build information
+ *
+ * Response is null-terminated string.
+ */
+#define EC_CMD_GET_BUILD_INFO 0x04
+
+/* Get chip info */
+#define EC_CMD_GET_CHIP_INFO 0x05
+
+struct ec_response_get_chip_info {
+       /* Null-terminated strings */
+       char vendor[32];
+       char name[32];
+       char revision[32];  /* Mask version */
+} __packed;
+
+/* Get board HW version */
+#define EC_CMD_GET_BOARD_VERSION 0x06
+
+struct ec_response_board_version {
+       uint16_t board_version;  /* A monotonously incrementing number. */
+} __packed;
+
+/*
+ * Read memory-mapped data.
+ *
+ * This is an alternate interface to memory-mapped data for bus protocols
+ * which don't support direct-mapped memory - I2C, SPI, etc.
+ *
+ * Response is params.size bytes of data.
+ */
+#define EC_CMD_READ_MEMMAP 0x07
+
+struct ec_params_read_memmap {
+       uint8_t offset;   /* Offset in memmap (EC_MEMMAP_*) */
+       uint8_t size;     /* Size to read in bytes */
+} __packed;
+
+/* Read versions supported for a command */
+#define EC_CMD_GET_CMD_VERSIONS 0x08
+
+struct ec_params_get_cmd_versions {
+       uint8_t cmd;      /* Command to check */
+} __packed;
+
+struct ec_response_get_cmd_versions {
+       /*
+        * Mask of supported versions; use EC_VER_MASK() to compare with a
+        * desired version.
+        */
+       uint32_t version_mask;
+} __packed;
+
+/*
+ * Check EC communcations status (busy). This is needed on i2c/spi but not
+ * on lpc since it has its own out-of-band busy indicator.
+ *
+ * lpc must read the status from the command register. Attempting this on
+ * lpc will overwrite the args/parameter space and corrupt its data.
+ */
+#define EC_CMD_GET_COMMS_STATUS                0x09
+
+/* Avoid using ec_status which is for return values */
+enum ec_comms_status {
+       EC_COMMS_STATUS_PROCESSING      = 1 << 0,       /* Processing cmd */
+};
+
+struct ec_response_get_comms_status {
+       uint32_t flags;         /* Mask of enum ec_comms_status */
+} __packed;
+
+
+/*****************************************************************************/
+/* Flash commands */
+
+/* Get flash info */
+#define EC_CMD_FLASH_INFO 0x10
+
+struct ec_response_flash_info {
+       /* Usable flash size, in bytes */
+       uint32_t flash_size;
+       /*
+        * Write block size.  Write offset and size must be a multiple
+        * of this.
+        */
+       uint32_t write_block_size;
+       /*
+        * Erase block size.  Erase offset and size must be a multiple
+        * of this.
+        */
+       uint32_t erase_block_size;
+       /*
+        * Protection block size.  Protection offset and size must be a
+        * multiple of this.
+        */
+       uint32_t protect_block_size;
+} __packed;
+
+/*
+ * Read flash
+ *
+ * Response is params.size bytes of data.
+ */
+#define EC_CMD_FLASH_READ 0x11
+
+struct ec_params_flash_read {
+       uint32_t offset;   /* Byte offset to read */
+       uint32_t size;     /* Size to read in bytes */
+} __packed;
+
+/* Write flash */
+#define EC_CMD_FLASH_WRITE 0x12
+
+struct ec_params_flash_write {
+       uint32_t offset;   /* Byte offset to write */
+       uint32_t size;     /* Size to write in bytes */
+       /*
+        * Data to write.  Could really use EC_PARAM_SIZE - 8, but tidiest to
+        * use a power of 2 so writes stay aligned.
+        */
+       uint8_t data[64];
+} __packed;
+
+/* Erase flash */
+#define EC_CMD_FLASH_ERASE 0x13
+
+struct ec_params_flash_erase {
+       uint32_t offset;   /* Byte offset to erase */
+       uint32_t size;     /* Size to erase in bytes */
+} __packed;
+
+/*
+ * Get/set flash protection.
+ *
+ * If mask!=0, sets/clear the requested bits of flags.  Depending on the
+ * firmware write protect GPIO, not all flags will take effect immediately;
+ * some flags require a subsequent hard reset to take effect.  Check the
+ * returned flags bits to see what actually happened.
+ *
+ * If mask=0, simply returns the current flags state.
+ */
+#define EC_CMD_FLASH_PROTECT 0x15
+#define EC_VER_FLASH_PROTECT 1  /* Command version 1 */
+
+/* Flags for flash protection */
+/* RO flash code protected when the EC boots */
+#define EC_FLASH_PROTECT_RO_AT_BOOT         (1 << 0)
+/*
+ * RO flash code protected now.  If this bit is set, at-boot status cannot
+ * be changed.
+ */
+#define EC_FLASH_PROTECT_RO_NOW             (1 << 1)
+/* Entire flash code protected now, until reboot. */
+#define EC_FLASH_PROTECT_ALL_NOW            (1 << 2)
+/* Flash write protect GPIO is asserted now */
+#define EC_FLASH_PROTECT_GPIO_ASSERTED      (1 << 3)
+/* Error - at least one bank of flash is stuck locked, and cannot be unlocked */
+#define EC_FLASH_PROTECT_ERROR_STUCK        (1 << 4)
+/*
+ * Error - flash protection is in inconsistent state.  At least one bank of
+ * flash which should be protected is not protected.  Usually fixed by
+ * re-requesting the desired flags, or by a hard reset if that fails.
+ */
+#define EC_FLASH_PROTECT_ERROR_INCONSISTENT (1 << 5)
+/* Entile flash code protected when the EC boots */
+#define EC_FLASH_PROTECT_ALL_AT_BOOT        (1 << 6)
+
+struct ec_params_flash_protect {
+       uint32_t mask;   /* Bits in flags to apply */
+       uint32_t flags;  /* New flags to apply */
+} __packed;
+
+struct ec_response_flash_protect {
+       /* Current value of flash protect flags */
+       uint32_t flags;
+       /*
+        * Flags which are valid on this platform.  This allows the caller
+        * to distinguish between flags which aren't set vs. flags which can't
+        * be set on this platform.
+        */
+       uint32_t valid_flags;
+       /* Flags which can be changed given the current protection state */
+       uint32_t writable_flags;
+} __packed;
+
+/*
+ * Note: commands 0x14 - 0x19 version 0 were old commands to get/set flash
+ * write protect.  These commands may be reused with version > 0.
+ */
+
+/* Get the region offset/size */
+#define EC_CMD_FLASH_REGION_INFO 0x16
+#define EC_VER_FLASH_REGION_INFO 1
+
+enum ec_flash_region {
+       /* Region which holds read-only EC image */
+       EC_FLASH_REGION_RO,
+       /* Region which holds rewritable EC image */
+       EC_FLASH_REGION_RW,
+       /*
+        * Region which should be write-protected in the factory (a superset of
+        * EC_FLASH_REGION_RO)
+        */
+       EC_FLASH_REGION_WP_RO,
+};
+
+struct ec_params_flash_region_info {
+       uint32_t region;  /* enum ec_flash_region */
+} __packed;
+
+struct ec_response_flash_region_info {
+       uint32_t offset;
+       uint32_t size;
+} __packed;
+
+/* Read/write VbNvContext */
+#define EC_CMD_VBNV_CONTEXT 0x17
+#define EC_VER_VBNV_CONTEXT 1
+#define EC_VBNV_BLOCK_SIZE 16
+
+enum ec_vbnvcontext_op {
+       EC_VBNV_CONTEXT_OP_READ,
+       EC_VBNV_CONTEXT_OP_WRITE,
+};
+
+struct ec_params_vbnvcontext {
+       uint32_t op;
+       uint8_t block[EC_VBNV_BLOCK_SIZE];
+} __packed;
+
+struct ec_response_vbnvcontext {
+       uint8_t block[EC_VBNV_BLOCK_SIZE];
+} __packed;
+
+/*****************************************************************************/
+/* PWM commands */
+
+/* Get fan target RPM */
+#define EC_CMD_PWM_GET_FAN_TARGET_RPM 0x20
+
+struct ec_response_pwm_get_fan_rpm {
+       uint32_t rpm;
+} __packed;
+
+/* Set target fan RPM */
+#define EC_CMD_PWM_SET_FAN_TARGET_RPM 0x21
+
+struct ec_params_pwm_set_fan_target_rpm {
+       uint32_t rpm;
+} __packed;
+
+/* Get keyboard backlight */
+#define EC_CMD_PWM_GET_KEYBOARD_BACKLIGHT 0x22
+
+struct ec_response_pwm_get_keyboard_backlight {
+       uint8_t percent;
+       uint8_t enabled;
+} __packed;
+
+/* Set keyboard backlight */
+#define EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT 0x23
+
+struct ec_params_pwm_set_keyboard_backlight {
+       uint8_t percent;
+} __packed;
+
+/* Set target fan PWM duty cycle */
+#define EC_CMD_PWM_SET_FAN_DUTY 0x24
+
+struct ec_params_pwm_set_fan_duty {
+       uint32_t percent;
+} __packed;
+
+/*****************************************************************************/
+/*
+ * Lightbar commands. This looks worse than it is. Since we only use one HOST
+ * command to say "talk to the lightbar", we put the "and tell it to do X" part
+ * into a subcommand. We'll make separate structs for subcommands with
+ * different input args, so that we know how much to expect.
+ */
+#define EC_CMD_LIGHTBAR_CMD 0x28
+
+struct rgb_s {
+       uint8_t r, g, b;
+};
+
+#define LB_BATTERY_LEVELS 4
+/* List of tweakable parameters. NOTE: It's __packed so it can be sent in a
+ * host command, but the alignment is the same regardless. Keep it that way.
+ */
+struct lightbar_params {
+       /* Timing */
+       int google_ramp_up;
+       int google_ramp_down;
+       int s3s0_ramp_up;
+       int s0_tick_delay[2];                   /* AC=0/1 */
+       int s0a_tick_delay[2];                  /* AC=0/1 */
+       int s0s3_ramp_down;
+       int s3_sleep_for;
+       int s3_ramp_up;
+       int s3_ramp_down;
+
+       /* Oscillation */
+       uint8_t new_s0;
+       uint8_t osc_min[2];                     /* AC=0/1 */
+       uint8_t osc_max[2];                     /* AC=0/1 */
+       uint8_t w_ofs[2];                       /* AC=0/1 */
+
+       /* Brightness limits based on the backlight and AC. */
+       uint8_t bright_bl_off_fixed[2];         /* AC=0/1 */
+       uint8_t bright_bl_on_min[2];            /* AC=0/1 */
+       uint8_t bright_bl_on_max[2];            /* AC=0/1 */
+
+       /* Battery level thresholds */
+       uint8_t battery_threshold[LB_BATTERY_LEVELS - 1];
+
+       /* Map [AC][battery_level] to color index */
+       uint8_t s0_idx[2][LB_BATTERY_LEVELS];   /* AP is running */
+       uint8_t s3_idx[2][LB_BATTERY_LEVELS];   /* AP is sleeping */
+
+       /* Color palette */
+       struct rgb_s color[8];                  /* 0-3 are Google colors */
+} __packed;
+
+struct ec_params_lightbar {
+       uint8_t cmd;                  /* Command (see enum lightbar_command) */
+       union {
+               struct {
+                       /* no args */
+               } dump, off, on, init, get_seq, get_params;
+
+               struct num {
+                       uint8_t num;
+               } brightness, seq, demo;
+
+               struct reg {
+                       uint8_t ctrl, reg, value;
+               } reg;
+
+               struct rgb {
+                       uint8_t led, red, green, blue;
+               } rgb;
+
+               struct lightbar_params set_params;
+       };
+} __packed;
+
+struct ec_response_lightbar {
+       union {
+               struct dump {
+                       struct {
+                               uint8_t reg;
+                               uint8_t ic0;
+                               uint8_t ic1;
+                       } vals[23];
+               } dump;
+
+               struct get_seq {
+                       uint8_t num;
+               } get_seq;
+
+               struct lightbar_params get_params;
+
+               struct {
+                       /* no return params */
+               } off, on, init, brightness, seq, reg, rgb, demo, set_params;
+       };
+} __packed;
+
+/* Lightbar commands */
+enum lightbar_command {
+       LIGHTBAR_CMD_DUMP = 0,
+       LIGHTBAR_CMD_OFF = 1,
+       LIGHTBAR_CMD_ON = 2,
+       LIGHTBAR_CMD_INIT = 3,
+       LIGHTBAR_CMD_BRIGHTNESS = 4,
+       LIGHTBAR_CMD_SEQ = 5,
+       LIGHTBAR_CMD_REG = 6,
+       LIGHTBAR_CMD_RGB = 7,
+       LIGHTBAR_CMD_GET_SEQ = 8,
+       LIGHTBAR_CMD_DEMO = 9,
+       LIGHTBAR_CMD_GET_PARAMS = 10,
+       LIGHTBAR_CMD_SET_PARAMS = 11,
+       LIGHTBAR_NUM_CMDS
+};
+
+/*****************************************************************************/
+/* Verified boot commands */
+
+/*
+ * Note: command code 0x29 version 0 was VBOOT_CMD in Link EVT; it may be
+ * reused for other purposes with version > 0.
+ */
+
+/* Verified boot hash command */
+#define EC_CMD_VBOOT_HASH 0x2A
+
+struct ec_params_vboot_hash {
+       uint8_t cmd;             /* enum ec_vboot_hash_cmd */
+       uint8_t hash_type;       /* enum ec_vboot_hash_type */
+       uint8_t nonce_size;      /* Nonce size; may be 0 */
+       uint8_t reserved0;       /* Reserved; set 0 */
+       uint32_t offset;         /* Offset in flash to hash */
+       uint32_t size;           /* Number of bytes to hash */
+       uint8_t nonce_data[64];  /* Nonce data; ignored if nonce_size=0 */
+} __packed;
+
+struct ec_response_vboot_hash {
+       uint8_t status;          /* enum ec_vboot_hash_status */
+       uint8_t hash_type;       /* enum ec_vboot_hash_type */
+       uint8_t digest_size;     /* Size of hash digest in bytes */
+       uint8_t reserved0;       /* Ignore; will be 0 */
+       uint32_t offset;         /* Offset in flash which was hashed */
+       uint32_t size;           /* Number of bytes hashed */
+       uint8_t hash_digest[64]; /* Hash digest data */
+} __packed;
+
+enum ec_vboot_hash_cmd {
+       EC_VBOOT_HASH_GET = 0,       /* Get current hash status */
+       EC_VBOOT_HASH_ABORT = 1,     /* Abort calculating current hash */
+       EC_VBOOT_HASH_START = 2,     /* Start computing a new hash */
+       EC_VBOOT_HASH_RECALC = 3,    /* Synchronously compute a new hash */
+};
+
+enum ec_vboot_hash_type {
+       EC_VBOOT_HASH_TYPE_SHA256 = 0, /* SHA-256 */
+};
+
+enum ec_vboot_hash_status {
+       EC_VBOOT_HASH_STATUS_NONE = 0, /* No hash (not started, or aborted) */
+       EC_VBOOT_HASH_STATUS_DONE = 1, /* Finished computing a hash */
+       EC_VBOOT_HASH_STATUS_BUSY = 2, /* Busy computing a hash */
+};
+
+/*
+ * Special values for offset for EC_VBOOT_HASH_START and EC_VBOOT_HASH_RECALC.
+ * If one of these is specified, the EC will automatically update offset and
+ * size to the correct values for the specified image (RO or RW).
+ */
+#define EC_VBOOT_HASH_OFFSET_RO 0xfffffffe
+#define EC_VBOOT_HASH_OFFSET_RW 0xfffffffd
+
+/*****************************************************************************/
+/* USB charging control commands */
+
+/* Set USB port charging mode */
+#define EC_CMD_USB_CHARGE_SET_MODE 0x30
+
+struct ec_params_usb_charge_set_mode {
+       uint8_t usb_port_id;
+       uint8_t mode;
+} __packed;
+
+/*****************************************************************************/
+/* Persistent storage for host */
+
+/* Maximum bytes that can be read/written in a single command */
+#define EC_PSTORE_SIZE_MAX 64
+
+/* Get persistent storage info */
+#define EC_CMD_PSTORE_INFO 0x40
+
+struct ec_response_pstore_info {
+       /* Persistent storage size, in bytes */
+       uint32_t pstore_size;
+       /* Access size; read/write offset and size must be a multiple of this */
+       uint32_t access_size;
+} __packed;
+
+/*
+ * Read persistent storage
+ *
+ * Response is params.size bytes of data.
+ */
+#define EC_CMD_PSTORE_READ 0x41
+
+struct ec_params_pstore_read {
+       uint32_t offset;   /* Byte offset to read */
+       uint32_t size;     /* Size to read in bytes */
+} __packed;
+
+/* Write persistent storage */
+#define EC_CMD_PSTORE_WRITE 0x42
+
+struct ec_params_pstore_write {
+       uint32_t offset;   /* Byte offset to write */
+       uint32_t size;     /* Size to write in bytes */
+       uint8_t data[EC_PSTORE_SIZE_MAX];
+} __packed;
+
+/*****************************************************************************/
+/* Real-time clock */
+
+/* RTC params and response structures */
+struct ec_params_rtc {
+       uint32_t time;
+} __packed;
+
+struct ec_response_rtc {
+       uint32_t time;
+} __packed;
+
+/* These use ec_response_rtc */
+#define EC_CMD_RTC_GET_VALUE 0x44
+#define EC_CMD_RTC_GET_ALARM 0x45
+
+/* These all use ec_params_rtc */
+#define EC_CMD_RTC_SET_VALUE 0x46
+#define EC_CMD_RTC_SET_ALARM 0x47
+
+/*****************************************************************************/
+/* Port80 log access */
+
+/* Get last port80 code from previous boot */
+#define EC_CMD_PORT80_LAST_BOOT 0x48
+
+struct ec_response_port80_last_boot {
+       uint16_t code;
+} __packed;
+
+/*****************************************************************************/
+/* Thermal engine commands */
+
+/* Set thershold value */
+#define EC_CMD_THERMAL_SET_THRESHOLD 0x50
+
+struct ec_params_thermal_set_threshold {
+       uint8_t sensor_type;
+       uint8_t threshold_id;
+       uint16_t value;
+} __packed;
+
+/* Get threshold value */
+#define EC_CMD_THERMAL_GET_THRESHOLD 0x51
+
+struct ec_params_thermal_get_threshold {
+       uint8_t sensor_type;
+       uint8_t threshold_id;
+} __packed;
+
+struct ec_response_thermal_get_threshold {
+       uint16_t value;
+} __packed;
+
+/* Toggle automatic fan control */
+#define EC_CMD_THERMAL_AUTO_FAN_CTRL 0x52
+
+/* Get TMP006 calibration data */
+#define EC_CMD_TMP006_GET_CALIBRATION 0x53
+
+struct ec_params_tmp006_get_calibration {
+       uint8_t index;
+} __packed;
+
+struct ec_response_tmp006_get_calibration {
+       float s0;
+       float b0;
+       float b1;
+       float b2;
+} __packed;
+
+/* Set TMP006 calibration data */
+#define EC_CMD_TMP006_SET_CALIBRATION 0x54
+
+struct ec_params_tmp006_set_calibration {
+       uint8_t index;
+       uint8_t reserved[3];  /* Reserved; set 0 */
+       float s0;
+       float b0;
+       float b1;
+       float b2;
+} __packed;
+
+/*****************************************************************************/
+/* CROS_EC - Matrix KeyBoard Protocol */
+
+/*
+ * Read key state
+ *
+ * Returns raw data for keyboard cols; see ec_response_cros_ec_info.cols for
+ * expected response size.
+ */
+#define EC_CMD_CROS_EC_STATE 0x60
+
+/* Provide information about the matrix : number of rows and columns */
+#define EC_CMD_CROS_EC_INFO 0x61
+
+struct ec_response_cros_ec_info {
+       uint32_t rows;
+       uint32_t cols;
+       uint8_t switches;
+} __packed;
+
+/* Simulate key press */
+#define EC_CMD_CROS_EC_SIMULATE_KEY 0x62
+
+struct ec_params_cros_ec_simulate_key {
+       uint8_t col;
+       uint8_t row;
+       uint8_t pressed;
+} __packed;
+
+/* Configure keyboard scanning */
+#define EC_CMD_CROS_EC_SET_CONFIG 0x64
+#define EC_CMD_CROS_EC_GET_CONFIG 0x65
+
+/* flags */
+enum cros_ec_config_flags {
+       EC_CROS_EC_FLAGS_ENABLE = 1,    /* Enable keyboard scanning */
+};
+
+enum cros_ec_config_valid {
+       EC_CROS_EC_VALID_SCAN_PERIOD            = 1 << 0,
+       EC_CROS_EC_VALID_POLL_TIMEOUT           = 1 << 1,
+       EC_CROS_EC_VALID_MIN_POST_SCAN_DELAY    = 1 << 3,
+       EC_CROS_EC_VALID_OUTPUT_SETTLE          = 1 << 4,
+       EC_CROS_EC_VALID_DEBOUNCE_DOWN          = 1 << 5,
+       EC_CROS_EC_VALID_DEBOUNCE_UP            = 1 << 6,
+       EC_CROS_EC_VALID_FIFO_MAX_DEPTH         = 1 << 7,
+};
+
+/* Configuration for our key scanning algorithm */
+struct ec_cros_ec_config {
+       uint32_t valid_mask;            /* valid fields */
+       uint8_t flags;          /* some flags (enum cros_ec_config_flags) */
+       uint8_t valid_flags;            /* which flags are valid */
+       uint16_t scan_period_us;        /* period between start of scans */
+       /* revert to interrupt mode after no activity for this long */
+       uint32_t poll_timeout_us;
+       /*
+        * minimum post-scan relax time. Once we finish a scan we check
+        * the time until we are due to start the next one. If this time is
+        * shorter this field, we use this instead.
+        */
+       uint16_t min_post_scan_delay_us;
+       /* delay between setting up output and waiting for it to settle */
+       uint16_t output_settle_us;
+       uint16_t debounce_down_us;      /* time for debounce on key down */
+       uint16_t debounce_up_us;        /* time for debounce on key up */
+       /* maximum depth to allow for fifo (0 = no keyscan output) */
+       uint8_t fifo_max_depth;
+} __packed;
+
+struct ec_params_cros_ec_set_config {
+       struct ec_cros_ec_config config;
+} __packed;
+
+struct ec_response_cros_ec_get_config {
+       struct ec_cros_ec_config config;
+} __packed;
+
+/* Run the key scan emulation */
+#define EC_CMD_KEYSCAN_SEQ_CTRL 0x66
+
+enum ec_keyscan_seq_cmd {
+       EC_KEYSCAN_SEQ_STATUS = 0,      /* Get status information */
+       EC_KEYSCAN_SEQ_CLEAR = 1,       /* Clear sequence */
+       EC_KEYSCAN_SEQ_ADD = 2,         /* Add item to sequence */
+       EC_KEYSCAN_SEQ_START = 3,       /* Start running sequence */
+       EC_KEYSCAN_SEQ_COLLECT = 4,     /* Collect sequence summary data */
+};
+
+enum ec_collect_flags {
+       /*
+        * Indicates this scan was processed by the EC. Due to timing, some
+        * scans may be skipped.
+        */
+       EC_KEYSCAN_SEQ_FLAG_DONE        = 1 << 0,
+};
+
+struct ec_collect_item {
+       uint8_t flags;          /* some flags (enum ec_collect_flags) */
+};
+
+struct ec_params_keyscan_seq_ctrl {
+       uint8_t cmd;    /* Command to send (enum ec_keyscan_seq_cmd) */
+       union {
+               struct {
+                       uint8_t active;         /* still active */
+                       uint8_t num_items;      /* number of items */
+                       /* Current item being presented */
+                       uint8_t cur_item;
+               } status;
+               struct {
+                       /*
+                        * Absolute time for this scan, measured from the
+                        * start of the sequence.
+                        */
+                       uint32_t time_us;
+                       uint8_t scan[0];        /* keyscan data */
+               } add;
+               struct {
+                       uint8_t start_item;     /* First item to return */
+                       uint8_t num_items;      /* Number of items to return */
+               } collect;
+       };
+} __packed;
+
+struct ec_result_keyscan_seq_ctrl {
+       union {
+               struct {
+                       uint8_t num_items;      /* Number of items */
+                       /* Data for each item */
+                       struct ec_collect_item item[0];
+               } collect;
+       };
+} __packed;
+
+/*****************************************************************************/
+/* Temperature sensor commands */
+
+/* Read temperature sensor info */
+#define EC_CMD_TEMP_SENSOR_GET_INFO 0x70
+
+struct ec_params_temp_sensor_get_info {
+       uint8_t id;
+} __packed;
+
+struct ec_response_temp_sensor_get_info {
+       char sensor_name[32];
+       uint8_t sensor_type;
+} __packed;
+
+/*****************************************************************************/
+
+/*
+ * Note: host commands 0x80 - 0x87 are reserved to avoid conflict with ACPI
+ * commands accidentally sent to the wrong interface.  See the ACPI section
+ * below.
+ */
+
+/*****************************************************************************/
+/* Host event commands */
+
+/*
+ * Host event mask params and response structures, shared by all of the host
+ * event commands below.
+ */
+struct ec_params_host_event_mask {
+       uint32_t mask;
+} __packed;
+
+struct ec_response_host_event_mask {
+       uint32_t mask;
+} __packed;
+
+/* These all use ec_response_host_event_mask */
+#define EC_CMD_HOST_EVENT_GET_B         0x87
+#define EC_CMD_HOST_EVENT_GET_SMI_MASK  0x88
+#define EC_CMD_HOST_EVENT_GET_SCI_MASK  0x89
+#define EC_CMD_HOST_EVENT_GET_WAKE_MASK 0x8d
+
+/* These all use ec_params_host_event_mask */
+#define EC_CMD_HOST_EVENT_SET_SMI_MASK  0x8a
+#define EC_CMD_HOST_EVENT_SET_SCI_MASK  0x8b
+#define EC_CMD_HOST_EVENT_CLEAR         0x8c
+#define EC_CMD_HOST_EVENT_SET_WAKE_MASK 0x8e
+#define EC_CMD_HOST_EVENT_CLEAR_B       0x8f
+
+/*****************************************************************************/
+/* Switch commands */
+
+/* Enable/disable LCD backlight */
+#define EC_CMD_SWITCH_ENABLE_BKLIGHT 0x90
+
+struct ec_params_switch_enable_backlight {
+       uint8_t enabled;
+} __packed;
+
+/* Enable/disable WLAN/Bluetooth */
+#define EC_CMD_SWITCH_ENABLE_WIRELESS 0x91
+
+struct ec_params_switch_enable_wireless {
+       uint8_t enabled;
+} __packed;
+
+/*****************************************************************************/
+/* GPIO commands. Only available on EC if write protect has been disabled. */
+
+/* Set GPIO output value */
+#define EC_CMD_GPIO_SET 0x92
+
+struct ec_params_gpio_set {
+       char name[32];
+       uint8_t val;
+} __packed;
+
+/* Get GPIO value */
+#define EC_CMD_GPIO_GET 0x93
+
+struct ec_params_gpio_get {
+       char name[32];
+} __packed;
+struct ec_response_gpio_get {
+       uint8_t val;
+} __packed;
+
+/*****************************************************************************/
+/* I2C commands. Only available when flash write protect is unlocked. */
+
+/* Read I2C bus */
+#define EC_CMD_I2C_READ 0x94
+
+struct ec_params_i2c_read {
+       uint16_t addr; /* 8-bit address (7-bit shifted << 1) */
+       uint8_t read_size; /* Either 8 or 16. */
+       uint8_t port;
+       uint8_t offset;
+} __packed;
+struct ec_response_i2c_read {
+       uint16_t data;
+} __packed;
+
+/* Write I2C bus */
+#define EC_CMD_I2C_WRITE 0x95
+
+struct ec_params_i2c_write {
+       uint16_t data;
+       uint16_t addr; /* 8-bit address (7-bit shifted << 1) */
+       uint8_t write_size; /* Either 8 or 16. */
+       uint8_t port;
+       uint8_t offset;
+} __packed;
+
+/*****************************************************************************/
+/* Charge state commands. Only available when flash write protect unlocked. */
+
+/* Force charge state machine to stop in idle mode */
+#define EC_CMD_CHARGE_FORCE_IDLE 0x96
+
+struct ec_params_force_idle {
+       uint8_t enabled;
+} __packed;
+
+/*****************************************************************************/
+/* Console commands. Only available when flash write protect is unlocked. */
+
+/* Snapshot console output buffer for use by EC_CMD_CONSOLE_READ. */
+#define EC_CMD_CONSOLE_SNAPSHOT 0x97
+
+/*
+ * Read next chunk of data from saved snapshot.
+ *
+ * Response is null-terminated string.  Empty string, if there is no more
+ * remaining output.
+ */
+#define EC_CMD_CONSOLE_READ 0x98
+
+/*****************************************************************************/
+
+/*
+ * Cut off battery power output if the battery supports.
+ *
+ * For unsupported battery, just don't implement this command and lets EC
+ * return EC_RES_INVALID_COMMAND.
+ */
+#define EC_CMD_BATTERY_CUT_OFF 0x99
+
+/*****************************************************************************/
+/* USB port mux control. */
+
+/*
+ * Switch USB mux or return to automatic switching.
+ */
+#define EC_CMD_USB_MUX 0x9a
+
+struct ec_params_usb_mux {
+       uint8_t mux;
+} __packed;
+
+/*****************************************************************************/
+/* LDOs / FETs control. */
+
+enum ec_ldo_state {
+       EC_LDO_STATE_OFF = 0,   /* the LDO / FET is shut down */
+       EC_LDO_STATE_ON = 1,    /* the LDO / FET is ON / providing power */
+};
+
+/*
+ * Switch on/off a LDO.
+ */
+#define EC_CMD_LDO_SET 0x9b
+
+struct ec_params_ldo_set {
+       uint8_t index;
+       uint8_t state;
+} __packed;
+
+/*
+ * Get LDO state.
+ */
+#define EC_CMD_LDO_GET 0x9c
+
+struct ec_params_ldo_get {
+       uint8_t index;
+} __packed;
+
+struct ec_response_ldo_get {
+       uint8_t state;
+} __packed;
+
+/*****************************************************************************/
+/* Power info. */
+
+/*
+ * Get power info.
+ */
+#define EC_CMD_POWER_INFO 0x9d
+
+struct ec_response_power_info {
+       uint32_t usb_dev_type;
+       uint16_t voltage_ac;
+       uint16_t voltage_system;
+       uint16_t current_system;
+       uint16_t usb_current_limit;
+} __packed;
+
+/*****************************************************************************/
+/* I2C passthru command */
+
+#define EC_CMD_I2C_PASSTHRU 0x9e
+
+/* Slave address is 10 (not 7) bit */
+#define EC_I2C_FLAG_10BIT      (1 << 16)
+
+/* Read data; if not present, message is a write */
+#define EC_I2C_FLAG_READ       (1 << 15)
+
+/* Mask for address */
+#define EC_I2C_ADDR_MASK       0x3ff
+
+#define EC_I2C_STATUS_NAK      (1 << 0) /* Transfer was not acknowledged */
+#define EC_I2C_STATUS_TIMEOUT  (1 << 1) /* Timeout during transfer */
+
+/* Any error */
+#define EC_I2C_STATUS_ERROR    (EC_I2C_STATUS_NAK | EC_I2C_STATUS_TIMEOUT)
+
+struct ec_params_i2c_passthru_msg {
+       uint16_t addr_flags;    /* I2C slave address (7 or 10 bits) and flags */
+       uint16_t len;           /* Number of bytes to write*/
+} __packed;
+
+struct ec_params_i2c_passthru {
+       uint8_t port;           /* I2C port number */
+       uint8_t num_msgs;       /* Number of messages */
+       struct ec_params_i2c_passthru_msg msg[];
+       /* Data for all messages is concatenated here */
+} __packed;
+
+struct ec_response_i2c_passthru {
+       uint8_t i2c_status;     /* Status flags (EC_I2C_STATUS_...) */
+       uint8_t num_msgs;       /* Number of messages processed */
+       uint8_t data[];         /* Data for all messages concatenated here */
+} __packed;
+
+
+/*****************************************************************************/
+/* Temporary debug commands. TODO: remove this crosbug.com/p/13849 */
+
+/*
+ * Dump charge state machine context.
+ *
+ * Response is a binary dump of charge state machine context.
+ */
+#define EC_CMD_CHARGE_DUMP 0xa0
+
+/*
+ * Set maximum battery charging current.
+ */
+#define EC_CMD_CHARGE_CURRENT_LIMIT 0xa1
+
+struct ec_params_current_limit {
+       uint32_t limit; /* in mA */
+} __packed;
+
+/*
+ * Set maximum external power current.
+ */
+#define EC_CMD_EXT_POWER_CURRENT_LIMIT 0xa2
+
+struct ec_params_ext_power_current_limit {
+       uint32_t limit; /* in mA */
+} __packed;
+
+/*****************************************************************************/
+/* Smart battery pass-through */
+
+/* Get / Set 16-bit smart battery registers */
+#define EC_CMD_SB_READ_WORD   0xb0
+#define EC_CMD_SB_WRITE_WORD  0xb1
+
+/* Get / Set string smart battery parameters
+ * formatted as SMBUS "block".
+ */
+#define EC_CMD_SB_READ_BLOCK  0xb2
+#define EC_CMD_SB_WRITE_BLOCK 0xb3
+
+struct ec_params_sb_rd {
+       uint8_t reg;
+} __packed;
+
+struct ec_response_sb_rd_word {
+       uint16_t value;
+} __packed;
+
+struct ec_params_sb_wr_word {
+       uint8_t reg;
+       uint16_t value;
+} __packed;
+
+struct ec_response_sb_rd_block {
+       uint8_t data[32];
+} __packed;
+
+struct ec_params_sb_wr_block {
+       uint8_t reg;
+       uint16_t data[32];
+} __packed;
+
+/*****************************************************************************/
+/* System commands */
+
+/*
+ * TODO: this is a confusing name, since it doesn't necessarily reboot the EC.
+ * Rename to "set image" or something similar.
+ */
+#define EC_CMD_REBOOT_EC 0xd2
+
+/* Command */
+enum ec_reboot_cmd {
+       EC_REBOOT_CANCEL = 0,        /* Cancel a pending reboot */
+       EC_REBOOT_JUMP_RO = 1,       /* Jump to RO without rebooting */
+       EC_REBOOT_JUMP_RW = 2,       /* Jump to RW without rebooting */
+       /* (command 3 was jump to RW-B) */
+       EC_REBOOT_COLD = 4,          /* Cold-reboot */
+       EC_REBOOT_DISABLE_JUMP = 5,  /* Disable jump until next reboot */
+       EC_REBOOT_HIBERNATE = 6      /* Hibernate EC */
+};
+
+/* Flags for ec_params_reboot_ec.reboot_flags */
+#define EC_REBOOT_FLAG_RESERVED0      (1 << 0)  /* Was recovery request */
+#define EC_REBOOT_FLAG_ON_AP_SHUTDOWN (1 << 1)  /* Reboot after AP shutdown */
+
+struct ec_params_reboot_ec {
+       uint8_t cmd;           /* enum ec_reboot_cmd */
+       uint8_t flags;         /* See EC_REBOOT_FLAG_* */
+} __packed;
+
+/*
+ * Get information on last EC panic.
+ *
+ * Returns variable-length platform-dependent panic information.  See panic.h
+ * for details.
+ */
+#define EC_CMD_GET_PANIC_INFO 0xd3
+
+/*****************************************************************************/
+/*
+ * ACPI commands
+ *
+ * These are valid ONLY on the ACPI command/data port.
+ */
+
+/*
+ * ACPI Read Embedded Controller
+ *
+ * This reads from ACPI memory space on the EC (EC_ACPI_MEM_*).
+ *
+ * Use the following sequence:
+ *
+ *    - Write EC_CMD_ACPI_READ to EC_LPC_ADDR_ACPI_CMD
+ *    - Wait for EC_LPC_CMDR_PENDING bit to clear
+ *    - Write address to EC_LPC_ADDR_ACPI_DATA
+ *    - Wait for EC_LPC_CMDR_DATA bit to set
+ *    - Read value from EC_LPC_ADDR_ACPI_DATA
+ */
+#define EC_CMD_ACPI_READ 0x80
+
+/*
+ * ACPI Write Embedded Controller
+ *
+ * This reads from ACPI memory space on the EC (EC_ACPI_MEM_*).
+ *
+ * Use the following sequence:
+ *
+ *    - Write EC_CMD_ACPI_WRITE to EC_LPC_ADDR_ACPI_CMD
+ *    - Wait for EC_LPC_CMDR_PENDING bit to clear
+ *    - Write address to EC_LPC_ADDR_ACPI_DATA
+ *    - Wait for EC_LPC_CMDR_PENDING bit to clear
+ *    - Write value to EC_LPC_ADDR_ACPI_DATA
+ */
+#define EC_CMD_ACPI_WRITE 0x81
+
+/*
+ * ACPI Query Embedded Controller
+ *
+ * This clears the lowest-order bit in the currently pending host events, and
+ * sets the result code to the 1-based index of the bit (event 0x00000001 = 1,
+ * event 0x80000000 = 32), or 0 if no event was pending.
+ */
+#define EC_CMD_ACPI_QUERY_EVENT 0x84
+
+/* Valid addresses in ACPI memory space, for read/write commands */
+/* Memory space version; set to EC_ACPI_MEM_VERSION_CURRENT */
+#define EC_ACPI_MEM_VERSION            0x00
+/*
+ * Test location; writing value here updates test compliment byte to (0xff -
+ * value).
+ */
+#define EC_ACPI_MEM_TEST               0x01
+/* Test compliment; writes here are ignored. */
+#define EC_ACPI_MEM_TEST_COMPLIMENT    0x02
+/* Keyboard backlight brightness percent (0 - 100) */
+#define EC_ACPI_MEM_KEYBOARD_BACKLIGHT 0x03
+
+/* Current version of ACPI memory address space */
+#define EC_ACPI_MEM_VERSION_CURRENT 1
+
+
+/*****************************************************************************/
+/*
+ * Special commands
+ *
+ * These do not follow the normal rules for commands.  See each command for
+ * details.
+ */
+
+/*
+ * Reboot NOW
+ *
+ * This command will work even when the EC LPC interface is busy, because the
+ * reboot command is processed at interrupt level.  Note that when the EC
+ * reboots, the host will reboot too, so there is no response to this command.
+ *
+ * Use EC_CMD_REBOOT_EC to reboot the EC more politely.
+ */
+#define EC_CMD_REBOOT 0xd1  /* Think "die" */
+
+/*
+ * Resend last response (not supported on LPC).
+ *
+ * Returns EC_RES_UNAVAILABLE if there is no response available - for example,
+ * there was no previous command, or the previous command's response was too
+ * big to save.
+ */
+#define EC_CMD_RESEND_RESPONSE 0xdb
+
+/*
+ * This header byte on a command indicate version 0. Any header byte less
+ * than this means that we are talking to an old EC which doesn't support
+ * versioning. In that case, we assume version 0.
+ *
+ * Header bytes greater than this indicate a later version. For example,
+ * EC_CMD_VERSION0 + 1 means we are using version 1.
+ *
+ * The old EC interface must not use commands 0dc or higher.
+ */
+#define EC_CMD_VERSION0 0xdc
+
+#endif  /* !__ACPI__ */
+
+#endif  /* __CROS_EC_COMMANDS_H */
diff --git a/sys/arch/armv7/exynos/exclock.c b/sys/arch/armv7/exynos/exclock.c
new file mode 100644 (file)
index 0000000..85f595a
--- /dev/null
@@ -0,0 +1,300 @@
+/* $OpenBSD: exclock.c,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
+/*
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/sysctl.h>
+#include <sys/device.h>
+#include <sys/evcount.h>
+#include <sys/socket.h>
+#include <sys/timeout.h>
+#include <machine/intr.h>
+#include <machine/bus.h>
+#include <machine/fdt.h>
+#include <armv7/armv7/armv7var.h>
+
+/* registers */
+#define CLOCK_APLL_CON0                                0x0100
+#define CLOCK_APLL_CON1                                0x0104
+#define CLOCK_BPLL_CON0                                0x0110
+#define CLOCK_BPLL_CON1                                0x0114
+#define CLOCK_EPLL_CON0                                0x0130
+#define CLOCK_EPLL_CON1                                0x0134
+#define CLOCK_EPLL_CON2                                0x0138
+#define CLOCK_VPLL_CON0                                0x0140
+#define CLOCK_VPLL_CON1                                0x0144
+#define CLOCK_VPLL_CON2                                0x0148
+#define CLOCK_CLK_DIV_CPU0                     0x0500
+#define CLOCK_CLK_DIV_CPU1                     0x0504
+#define CLOCK_CLK_DIV_TOP0                     0x0510
+#define CLOCK_CLK_DIV_TOP1                     0x0514
+#define CLOCK_PLL_DIV2_SEL                     0x0A24
+#define CLOCK_MPLL_CON0                                0x4100
+#define CLOCK_MPLL_CON1                                0x4104
+
+/* bits and bytes */
+#define MPLL_FOUT_SEL_SHIFT                    0x4
+#define MPLL_FOUT_SEL_MASK                     0x1
+#define BPLL_FOUT_SEL_SHIFT                    0x0
+#define BPLL_FOUT_SEL_MASK                     0x1
+
+#define HCLK_FREQ                              24000
+
+#define HREAD4(sc, reg)                                                        \
+       (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
+#define HWRITE4(sc, reg, val)                                          \
+       bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+#define HSET4(sc, reg, bits)                                           \
+       HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
+#define HCLR4(sc, reg, bits)                                           \
+       HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
+
+struct exclock_softc {
+       struct device           sc_dev;
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh;
+};
+
+enum clocks {
+       /* OSC */
+       OSC,            /* 24 MHz OSC */
+
+       /* PLLs */
+       APLL,           /* ARM core clock */
+       MPLL,           /* System bus clock for memory controller */
+       BPLL,           /* Graphic 3D processor clock and 1066 MHz clock for memory controller if necessary */
+       CPLL,           /* Multi Format Video Hardware Codec clock */
+       GPLL,           /* Graphic 3D processor clock or other clocks for DVFS flexibility */
+       EPLL,           /* Audio interface clocks and clocks for other external device interfaces */
+       VPLL,           /* dithered PLL, helps to reduce the EMI of display and camera */
+};
+
+struct exclock_softc *exclock_sc;
+
+int exclock_match(struct device *parent, void *v, void *aux);
+void exclock_attach(struct device *parent, struct device *self, void *args);
+int exclock_cpuspeed(int *);
+unsigned int exclock_decode_pll_clk(enum clocks, unsigned int, unsigned int);
+unsigned int exclock_get_pll_clk(enum clocks);
+unsigned int exclock_get_armclk(void);
+unsigned int exclock_get_i2cclk(void);
+
+struct cfattach        exclock_ca = {
+       sizeof (struct exclock_softc), NULL, exclock_attach
+};
+struct cfattach        exclock_fdt_ca = {
+       sizeof (struct exclock_softc), exclock_match, exclock_attach
+};
+
+struct cfdriver exclock_cd = {
+       NULL, "exclock", DV_DULL
+};
+
+int
+exclock_match(struct device *parent, void *v, void *aux)
+{
+       struct armv7_attach_args *aa = aux;
+
+       if (fdt_node_compatible("samsung,exynos5250-clock", aa->aa_node))
+               return 1;
+
+       return 0;
+}
+
+void
+exclock_attach(struct device *parent, struct device *self, void *args)
+{
+       struct armv7_attach_args *aa = args;
+       struct exclock_softc *sc = (struct exclock_softc *) self;
+       struct fdt_memory mem;
+
+       exclock_sc = sc;
+       sc->sc_iot = aa->aa_iot;
+       if (aa->aa_node) {
+               if (fdt_get_memory_address(aa->aa_node, 0, &mem))
+                       panic("%s: could not extract memory data from FDT",
+                           __func__);
+       } else {
+               mem.addr = aa->aa_dev->mem[0].addr;
+               mem.size = aa->aa_dev->mem[0].size;
+       }
+       if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh))
+               panic("%s: bus_space_map failed!", __func__);
+
+       printf(": Exynos 5 CPU freq: %d MHz",
+           exclock_get_armclk() / 1000);
+
+       printf("\n");
+
+       cpu_cpuspeed = exclock_cpuspeed;
+}
+
+int
+exclock_cpuspeed(int *freq)
+{
+       *freq = exclock_get_armclk() / 1000;
+       return (0);
+}
+
+unsigned int
+exclock_decode_pll_clk(enum clocks pll, unsigned int r, unsigned int k)
+{
+       uint32_t m, p, s = 0, mask, fout, freq;
+       /*
+        * APLL_CON: MIDV [25:16]
+        * MPLL_CON: MIDV [25:16]
+        * EPLL_CON: MIDV [24:16]
+        * VPLL_CON: MIDV [24:16]
+        * BPLL_CON: MIDV [25:16]: Exynos5
+        */
+
+       switch (pll)
+       {
+       case APLL:
+       case MPLL:
+       case BPLL:
+               mask = 0x3ff;
+               break;
+       default:
+               mask = 0x1ff;
+       }
+
+       m = (r >> 16) & mask;
+
+       /* PDIV [13:8] */
+       p = (r >> 8) & 0x3f;
+       /* SDIV [2:0] */
+       s = r & 0x7;
+
+       freq = HCLK_FREQ;
+
+       if (pll == EPLL) {
+               k = k & 0xffff;
+               /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */
+               fout = (m + k / 65536) * (freq / (p * (1 << s)));
+       } else if (pll == VPLL) {
+               k = k & 0xfff;
+               /* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */
+               fout = (m + k / 1024) * (freq / (p * (1 << s)));
+       } else {
+               /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
+               fout = m * (freq / (p * (1 << s)));
+       }
+
+       return fout;
+}
+
+unsigned int
+exclock_get_pll_clk(enum clocks pll)
+{
+       struct exclock_softc *sc = exclock_sc;
+       uint32_t freq;
+
+       switch (pll) {
+       case APLL:
+               freq = exclock_decode_pll_clk(pll,
+                   HREAD4(sc, CLOCK_APLL_CON0),
+                   0);
+               break;
+       case MPLL:
+               freq = exclock_decode_pll_clk(pll,
+                   HREAD4(sc, CLOCK_MPLL_CON0),
+                   0);
+               break;
+       case BPLL:
+               freq = exclock_decode_pll_clk(pll,
+                   HREAD4(sc, CLOCK_BPLL_CON0),
+                   0);
+               break;
+       case EPLL:
+               freq = exclock_decode_pll_clk(pll,
+                   HREAD4(sc, CLOCK_EPLL_CON0),
+                   HREAD4(sc, CLOCK_EPLL_CON1));
+               break;
+       case VPLL:
+               freq = exclock_decode_pll_clk(pll,
+                   HREAD4(sc, CLOCK_VPLL_CON0),
+                   HREAD4(sc, CLOCK_VPLL_CON1));
+               break;
+       default:
+               return 0;
+       }
+
+       /*
+        * According to the user manual, in EVT1 MPLL and BPLL always gives
+        * 1.6GHz clock, so divide by 2 to get 800MHz MPLL clock.
+        */
+       if (pll == MPLL || pll == BPLL) {
+               uint32_t freq_sel;
+               uint32_t pll_div2_sel = HREAD4(sc, CLOCK_PLL_DIV2_SEL);
+
+               switch (pll) {
+               case MPLL:
+                       freq_sel = (pll_div2_sel >> MPLL_FOUT_SEL_SHIFT)
+                                       & MPLL_FOUT_SEL_MASK;
+                       break;
+               case BPLL:
+                       freq_sel = (pll_div2_sel >> BPLL_FOUT_SEL_SHIFT)
+                                       & BPLL_FOUT_SEL_MASK;
+                       break;
+               default:
+                       freq_sel = -1;
+                       break;
+               }
+
+               if (freq_sel == 0)
+                       freq /= 2;
+       }
+
+       return freq;
+}
+
+unsigned int
+exclock_get_armclk()
+{
+       struct exclock_softc *sc = exclock_sc;
+       uint32_t div, armclk, arm_ratio, arm2_ratio;
+
+       div = HREAD4(sc, CLOCK_CLK_DIV_CPU0);
+
+       /* ARM_RATIO: [2:0], ARM2_RATIO: [30:28] */
+       arm_ratio = (div >> 0) & 0x7;
+       arm2_ratio = (div >> 28) & 0x7;
+
+       armclk = exclock_get_pll_clk(APLL) / (arm_ratio + 1);
+       armclk /= (arm2_ratio + 1);
+
+       return armclk;
+}
+
+unsigned int
+exclock_get_i2cclk()
+{
+       struct exclock_softc *sc = exclock_sc;
+       uint32_t aclk_66, aclk_66_pre, div, ratio;
+
+       div = HREAD4(sc, CLOCK_CLK_DIV_TOP1);
+       ratio = (div >> 24) & 0x7;
+       aclk_66_pre = exclock_get_pll_clk(MPLL) / (ratio + 1);
+       div = HREAD4(sc, CLOCK_CLK_DIV_TOP0);
+       ratio = (div >> 0) & 0x7;
+       aclk_66 = aclk_66_pre / (ratio + 1);
+
+       return aclk_66;
+}
diff --git a/sys/arch/armv7/exynos/exclockvar.h b/sys/arch/armv7/exynos/exclockvar.h
new file mode 100644 (file)
index 0000000..a5e3fd7
--- /dev/null
@@ -0,0 +1,23 @@
+/* $OpenBSD: exclockvar.h,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
+/*
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef EXCLOCKVAR_H
+#define EXCLOCKVAR_H
+
+unsigned int exclock_get_i2cclk(void);
+
+#endif /* EXCLOCKVAR_H */
diff --git a/sys/arch/armv7/exynos/exdisplay.c b/sys/arch/armv7/exynos/exdisplay.c
new file mode 100644 (file)
index 0000000..6c7663f
--- /dev/null
@@ -0,0 +1,290 @@
+/* $OpenBSD: exdisplay.c,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
+/*
+ * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/evcount.h>
+#include <sys/socket.h>
+#include <sys/timeout.h>
+
+#include <dev/cons.h>
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsdisplayvar.h>
+#include <dev/wscons/wscons_callbacks.h>
+#include <dev/wsfont/wsfont.h>
+#include <dev/rasops/rasops.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+#include <machine/fdt.h>
+#include <armv7/armv7/armv7var.h>
+
+/* registers */
+
+struct exdisplay_softc {
+       struct device            sc_dev;
+       bus_space_tag_t          sc_iot;
+       bus_space_handle_t       sc_ioh;
+       struct rasops_info      *ro;
+};
+
+int exdisplay_match(struct device *parent, void *v, void *aux);
+void exdisplay_attach(struct device *parent, struct device *self, void *args);
+int exdisplay_cnattach(bus_space_tag_t iot, bus_addr_t iobase, size_t size);
+void exdisplay_setup_rasops(struct rasops_info *rinfo, struct wsscreen_descr *descr);
+
+struct cfattach        exdisplay_ca = {
+       sizeof (struct exdisplay_softc), NULL, exdisplay_attach
+};
+struct cfattach        exdisplay_fdt_ca = {
+       sizeof (struct exdisplay_softc), exdisplay_match, exdisplay_attach
+};
+
+struct cfdriver exdisplay_cd = {
+       NULL, "exdisplay", DV_DULL
+};
+
+int exdisplay_wsioctl(void *, u_long, caddr_t, int, struct proc *);
+paddr_t exdisplay_wsmmap(void *, off_t, int);
+int exdisplay_alloc_screen(void *, const struct wsscreen_descr *,
+    void **, int *, int *, long *);
+void exdisplay_free_screen(void *, void *);
+int exdisplay_show_screen(void *, void *, int,
+    void (*)(void *, int, int), void *);
+void exdisplay_doswitch(void *, void *);
+int exdisplay_load_font(void *, void *, struct wsdisplay_font *);
+int exdisplay_list_font(void *, struct wsdisplay_font *);
+int exdisplay_getchar(void *, int, int, struct wsdisplay_charcell *);
+void exdisplay_burner(void *, u_int, u_int);
+
+struct rasops_info exdisplay_ri;
+struct wsscreen_descr exdisplay_stdscreen = {
+       "std"
+};
+
+const struct wsscreen_descr *exdisplay_scrlist[] = {
+       &exdisplay_stdscreen,
+};
+
+struct wsscreen_list exdisplay_screenlist = {
+       nitems(exdisplay_scrlist), exdisplay_scrlist
+};
+
+struct wsdisplay_accessops exdisplay_accessops = {
+       .ioctl = exdisplay_wsioctl,
+       .mmap = exdisplay_wsmmap,
+       .alloc_screen = exdisplay_alloc_screen,
+       .free_screen = exdisplay_free_screen,
+       .show_screen = exdisplay_show_screen,
+       .getchar = exdisplay_getchar,
+       .load_font = exdisplay_load_font,
+       .list_font = exdisplay_list_font,
+       .burn_screen = exdisplay_burner
+};
+
+int
+exdisplay_match(struct device *parent, void *v, void *aux)
+{
+       struct armv7_attach_args *aa = aux;
+
+       if (fdt_node_compatible("samsung,exynos5250-fimd", aa->aa_node))
+               return 1;
+
+       return 0;
+}
+
+void
+exdisplay_attach(struct device *parent, struct device *self, void *args)
+{
+       struct armv7_attach_args *aa = args;
+       struct exdisplay_softc *sc = (struct exdisplay_softc *) self;
+       struct wsemuldisplaydev_attach_args waa;
+       struct rasops_info *ri = &exdisplay_ri;
+       struct fdt_memory mem;
+
+       if (aa->aa_node == NULL) {
+               printf(": not configured without FDT\n");
+               return;
+       }
+
+       sc->sc_iot = aa->aa_iot;
+       if (fdt_get_memory_address(aa->aa_node, 0, &mem))
+               panic("%s: could not extract memory data from FDT",
+                   __func__);
+
+       if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh))
+               panic("%s: bus_space_map failed!", __func__);
+
+       printf("\n");
+
+#if notyet
+       /* FIXME: Set up framebuffer instead of re-using. */
+       if (!fdt_find_compatible("simple-framebuffer")) {
+               long defattr;
+
+               ri->ri_bits = (u_char *)sc->sc_fbioh;
+               exdisplay_setup_rasops(ri, &exdisplay_stdscreen);
+
+               ri->ri_ops.alloc_attr(ri->ri_active, 0, 0, 0, &defattr);
+               wsdisplay_cnattach(&exdisplay_stdscreen, ri->ri_active,
+                   0, 0, defattr);
+       }
+#endif
+
+       sc->ro = ri;
+
+       waa.console = 1;
+       waa.scrdata = &exdisplay_screenlist;
+       waa.accessops = &exdisplay_accessops;
+       waa.accesscookie = sc;
+       waa.defaultscreens = 0;
+
+       printf("%s: %dx%d\n", sc->sc_dev.dv_xname, ri->ri_width, ri->ri_height);
+
+       config_found(self, &waa, wsemuldisplaydevprint);
+}
+
+int
+exdisplay_cnattach(bus_space_tag_t iot, bus_addr_t iobase, size_t size)
+{
+       struct wsscreen_descr *descr = &exdisplay_stdscreen;
+       struct rasops_info *ri = &exdisplay_ri;
+       long defattr;
+
+       if (bus_space_map(iot, iobase, size, 0, (bus_space_handle_t *)&ri->ri_bits))
+               return ENOMEM;
+
+       exdisplay_setup_rasops(ri, descr);
+
+       /* assumes 16 bpp */
+       ri->ri_ops.alloc_attr(ri, 0, 0, 0, &defattr);
+
+       wsdisplay_cnattach(descr, ri, ri->ri_ccol, ri->ri_crow, defattr);
+
+       return 0;
+}
+
+void
+exdisplay_setup_rasops(struct rasops_info *rinfo, struct wsscreen_descr *descr)
+{
+       rinfo->ri_flg = RI_CLEAR;
+       rinfo->ri_depth = 16;
+       rinfo->ri_width = 1366;
+       rinfo->ri_height = 768;
+       rinfo->ri_stride = rinfo->ri_width * rinfo->ri_depth / 8;
+
+       /* swap B and R */
+       if (rinfo->ri_depth == 16) {
+               rinfo->ri_rnum = 5;
+               rinfo->ri_rpos = 11;
+               rinfo->ri_gnum = 6;
+               rinfo->ri_gpos = 5;
+               rinfo->ri_bnum = 5;
+               rinfo->ri_bpos = 0;
+       }
+
+       wsfont_init();
+       rinfo->ri_wsfcookie = wsfont_find(NULL, 8, 0, 0);
+       wsfont_lock(rinfo->ri_wsfcookie, &rinfo->ri_font,
+           WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R);
+
+       /* get rasops to compute screen size the first time */
+       rasops_init(rinfo, 200, 200);
+
+       descr->nrows = rinfo->ri_rows;
+       descr->ncols = rinfo->ri_cols;
+       descr->capabilities = rinfo->ri_caps;
+       descr->textops = &rinfo->ri_ops;
+}
+
+int
+exdisplay_wsioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+       return (-1);
+}
+
+paddr_t
+exdisplay_wsmmap(void *v, off_t off, int prot)
+{
+       return (-1);
+}
+
+int
+exdisplay_alloc_screen(void *v, const struct wsscreen_descr *type,
+    void **cookiep, int *curxp, int *curyp, long *attrp)
+{
+       struct exdisplay_softc *sc = v;
+       struct rasops_info *ri = sc->ro;
+
+       return rasops_alloc_screen(ri, cookiep, curxp, curyp, attrp);
+}
+
+void
+exdisplay_free_screen(void *v, void *cookie)
+{
+       struct exdisplay_softc *sc = v;
+       struct rasops_info *ri = sc->ro;
+
+       return rasops_free_screen(ri, cookie);
+}
+
+int
+exdisplay_show_screen(void *v, void *cookie, int waitok,
+    void (*cb)(void *, int, int), void *cbarg)
+{
+       return (0);
+}
+
+void
+exdisplay_doswitch(void *v, void *dummy)
+{
+}
+
+int
+exdisplay_getchar(void *v, int row, int col, struct wsdisplay_charcell *cell)
+{
+       struct exdisplay_softc *sc = v;
+       struct rasops_info *ri = sc->ro;
+
+       return rasops_getchar(ri, row, col, cell);
+}
+
+int
+exdisplay_load_font(void *v, void *cookie, struct wsdisplay_font *font)
+{
+       struct exdisplay_softc *sc = v;
+       struct rasops_info *ri = sc->ro;
+
+       return rasops_load_font(ri, cookie, font);
+}
+
+int
+exdisplay_list_font(void *v, struct wsdisplay_font *font)
+{
+       struct exdisplay_softc *sc = v;
+       struct rasops_info *ri = sc->ro;
+
+       return rasops_list_font(ri, font);
+}
+
+void
+exdisplay_burner(void *v, u_int on, u_int flags)
+{
+}
diff --git a/sys/arch/armv7/exynos/exdisplayvar.h b/sys/arch/armv7/exynos/exdisplayvar.h
new file mode 100644 (file)
index 0000000..853e683
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+int exdisplay_cnattach(bus_space_tag_t iot, bus_addr_t iobase, size_t size);
diff --git a/sys/arch/armv7/exynos/exdog.c b/sys/arch/armv7/exynos/exdog.c
new file mode 100644 (file)
index 0000000..d5e285a
--- /dev/null
@@ -0,0 +1,146 @@
+/* $OpenBSD: exdog.c,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
+/*
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/evcount.h>
+#include <sys/socket.h>
+#include <sys/timeout.h>
+#include <machine/bus.h>
+#include <machine/fdt.h>
+#include <machine/intr.h>
+#include <armv7/armv7/armv7var.h>
+
+/* registers */
+#define WTCON          0x00
+#define WTDAT          0x04
+#define WTCNT          0x08
+#define WTCLRINT       0x0C
+
+/* bits and bytes */
+#define WTCON_RESET            (1 << 0)
+#define WTCON_INT              (1 << 2)
+#define WTCON_CLKSEL_16                (0x0 << 3)
+#define WTCON_CLKSEL_32                (0x1 << 3)
+#define WTCON_CLKSEL_64                (0x2 << 3)
+#define WTCON_CLKSEL_128       (0x3 << 3)
+#define WTCON_EN               (1 << 5)
+#define WTCON_PRESCALER(x)     (((x) & 0xff) << 8)
+
+struct exdog_softc {
+       struct device           sc_dev;
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh;
+};
+
+struct exdog_softc *exdog_sc;
+
+int exdog_match(struct device *parent, void *v, void *aux);
+void exdog_attach(struct device *parent, struct device *self, void *args);
+void exdog_stop(void);
+void exdog_reset(void);
+
+struct cfattach        exdog_ca = {
+       sizeof (struct exdog_softc), NULL, exdog_attach
+};
+struct cfattach        exdog_fdt_ca = {
+       sizeof (struct exdog_softc), exdog_match, exdog_attach
+};
+
+struct cfdriver exdog_cd = {
+       NULL, "exdog", DV_DULL
+};
+
+int
+exdog_match(struct device *parent, void *v, void *aux)
+{
+       struct armv7_attach_args *aa = aux;
+
+       if (fdt_node_compatible("samsung,exynos5250-wdt", aa->aa_node))
+               return 1;
+
+       return 0;
+}
+
+void
+exdog_attach(struct device *parent, struct device *self, void *args)
+{
+       struct armv7_attach_args *aa = args;
+       struct exdog_softc *sc = (struct exdog_softc *) self;
+       struct fdt_memory mem;
+
+       sc->sc_iot = aa->aa_iot;
+       if (aa->aa_node) {
+               if (fdt_get_memory_address(aa->aa_node, 0, &mem))
+                       panic("%s: could not extract memory data from FDT",
+                           __func__);
+       } else {
+               mem.addr = aa->aa_dev->mem[0].addr;
+               mem.size = aa->aa_dev->mem[0].size;
+       }
+       if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh))
+               panic("%s: bus_space_map failed!", __func__);
+
+       printf("\n");
+       exdog_sc = sc;
+}
+
+void
+exdog_stop()
+{
+       uint32_t wtcon;
+
+       if (exdog_sc == NULL)
+               return;
+
+       wtcon = bus_space_read_4(exdog_sc->sc_iot, exdog_sc->sc_ioh, WTCON);
+
+       wtcon &= ~(WTCON_EN | WTCON_INT | WTCON_RESET);
+
+       bus_space_write_4(exdog_sc->sc_iot, exdog_sc->sc_ioh, WTCON, wtcon);
+}
+
+void
+exdog_reset()
+{
+       uint32_t wtcon;
+
+       if (exdog_sc == NULL)
+               return;
+
+       /* disable watchdog */
+       exdog_stop();
+
+       wtcon = bus_space_read_4(exdog_sc->sc_iot, exdog_sc->sc_ioh, WTCON);
+
+       wtcon |= WTCON_EN | WTCON_CLKSEL_128;
+       wtcon &= ~WTCON_INT;
+       wtcon |= WTCON_RESET;
+       wtcon |= WTCON_PRESCALER(0xff);
+
+       /* set timeout to 1 */
+       bus_space_write_4(exdog_sc->sc_iot, exdog_sc->sc_ioh, WTDAT, 1);
+       bus_space_write_4(exdog_sc->sc_iot, exdog_sc->sc_ioh, WTCNT, 1);
+
+       /* kick off the watchdog */
+       bus_space_write_4(exdog_sc->sc_iot, exdog_sc->sc_ioh, WTCON, wtcon);
+
+       delay(100000);
+}
diff --git a/sys/arch/armv7/exynos/exehci.c b/sys/arch/armv7/exynos/exehci.c
new file mode 100644 (file)
index 0000000..a73f628
--- /dev/null
@@ -0,0 +1,321 @@
+/*     $OpenBSD: exehci.c,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
+/*
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/rwlock.h>
+#include <sys/timeout.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
+#include <dev/usb/usb_mem.h>
+
+#include <armv7/armv7/armv7var.h>
+#include <armv7/exynos/exsysregvar.h>
+#include <armv7/exynos/expowervar.h>
+#include <armv7/exynos/exgpiovar.h>
+
+#include <dev/usb/ehcireg.h>
+#include <dev/usb/ehcivar.h>
+
+/* registers */
+#define USBPHY_CTRL0                   0x00
+#define USBPHY_TUNE0                   0x04
+#define HSICPHY_CTRL1                  0x10
+#define HSICPHY_TUNE1                  0x14
+#define HSICPHY_CTRL2                  0x20
+#define HSICPHY_TUNE2                  0x24
+#define EHCI_CTRL                      0x30
+#define OHCI_CTRL                      0x34
+#define USBOTG_SYS                     0x38
+#define USBOTG_TUNE                    0x40
+
+/* bits and bytes */
+#define CLK_24MHZ                      5
+
+#define HOST_CTRL0_PHYSWRSTALL         (1U << 31)
+#define HOST_CTRL0_COMMONON_N          (1 << 9)
+#define HOST_CTRL0_SIDDQ               (1 << 6)
+#define HOST_CTRL0_FORCESLEEP          (1 << 5)
+#define HOST_CTRL0_FORCESUSPEND                (1 << 4)
+#define HOST_CTRL0_WORDINTERFACE       (1 << 3)
+#define HOST_CTRL0_UTMISWRST           (1 << 2)
+#define HOST_CTRL0_LINKSWRST           (1 << 1)
+#define HOST_CTRL0_PHYSWRST            (1 << 0)
+
+#define HOST_CTRL0_FSEL_MASK           (7 << 16)
+
+#define EHCI_CTRL_ENAINCRXALIGN                (1 << 29)
+#define EHCI_CTRL_ENAINCR4             (1 << 28)
+#define EHCI_CTRL_ENAINCR8             (1 << 27)
+#define EHCI_CTRL_ENAINCR16            (1 << 26)
+
+int    exehci_match(struct device *, void *, void *);
+void   exehci_attach(struct device *, struct device *, void *);
+int    exehci_detach(struct device *, int);
+
+struct exehci_softc {
+       struct device           sc_dev;
+       struct ehci_softc       *sc_ehci;
+       void                    *sc_ih;
+       bus_dma_tag_t           sc_dmat;
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh;
+       bus_size_t              sc_size;
+       bus_space_handle_t      ph_ioh;
+};
+
+struct cfdriver exehci_cd = {
+       NULL, "exehci", DV_DULL
+};
+
+struct cfattach exehci_ca = {
+       sizeof (struct exehci_softc), NULL, exehci_attach,
+       exehci_detach, NULL
+};
+struct cfattach exehci_fdt_ca = {
+       sizeof (struct exehci_softc), exehci_match, exehci_attach,
+       exehci_detach, NULL
+};
+
+void   exehci_setup(struct exehci_softc *);
+
+int
+exehci_match(struct device *parent, void *v, void *aux)
+{
+       struct armv7_attach_args *aa = aux;
+
+       if (fdt_node_compatible("samsung,exynos4210-ehci", aa->aa_node))
+               return 1;
+
+       return 0;
+}
+
+void
+exehci_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct exehci_softc             *sc = (struct exehci_softc *)self;
+       struct ehci_softc               *esc;
+       struct armv7_attach_args        *aa = aux;
+       struct fdt_memory                hmem, pmem;
+       int                              irq;
+       usbd_status                      r;
+
+       sc->sc_iot = aa->aa_iot;
+       sc->sc_dmat = aa->aa_dmat;
+
+       if (aa->aa_node) {
+               uint32_t ints[3];
+
+               if (fdt_get_memory_address(aa->aa_node, 0, &hmem))
+                       panic("%s: could not extract memory data from FDT",
+                           __func__);
+
+               /* XXX: In a different way, please. */
+               void *node = fdt_find_compatible("samsung,exynos5250-usb2-phy");
+               if (node == NULL || fdt_get_memory_address(node, 0, &pmem))
+                       panic("%s: could not extract phy data from FDT",
+                           __func__);
+
+               /* TODO: Add interrupt FDT API. */
+               if (fdt_node_property_ints(aa->aa_node, "interrupts",
+                   ints, 3) != 3)
+                       panic("%s: could not extract interrupt data from FDT",
+                           __func__);
+
+               irq = ints[1];
+       } else {
+               hmem.addr = aa->aa_dev->mem[0].addr;
+               hmem.size = aa->aa_dev->mem[0].size;
+               pmem.addr = aa->aa_dev->mem[1].addr;
+               pmem.size = aa->aa_dev->mem[1].size;
+               irq = aa->aa_dev->irq[0];
+       }
+
+       /* Map I/O space */
+       sc->sc_size = hmem.size;
+       if (bus_space_map(sc->sc_iot, hmem.addr, hmem.size, 0, &sc->sc_ioh)) {
+               printf(": cannot map mem space\n");
+               goto out;
+       }
+
+       if (bus_space_map(sc->sc_iot, pmem.addr, pmem.size, 0, &sc->ph_ioh)) {
+               printf(": cannot map mem space\n");
+               goto pmem;
+       }
+
+       printf("\n");
+
+       exehci_setup(sc);
+
+       if ((esc = (struct ehci_softc *)config_found(self, NULL, NULL)) == NULL)
+               goto hmem;
+
+       sc->sc_ehci = esc;
+       esc->iot = sc->sc_iot;
+       esc->ioh = sc->sc_ioh;
+       esc->sc_bus.dmatag = aa->aa_dmat;
+
+       sc->sc_ih = arm_intr_establish(irq, IPL_USB,
+           ehci_intr, esc, esc->sc_bus.bdev.dv_xname);
+       if (sc->sc_ih == NULL) {
+               printf(": unable to establish interrupt\n");
+               goto hmem;
+       }
+
+       strlcpy(esc->sc_vendor, "Exynos 5", sizeof(esc->sc_vendor));
+       r = ehci_init(esc);
+       if (r != USBD_NORMAL_COMPLETION) {
+               printf("%s: init failed, error=%d\n",
+                   esc->sc_bus.bdev.dv_xname, r);
+               goto intr;
+       }
+
+       printf("\n");
+
+       config_found((struct device *)esc, &esc->sc_bus, usbctlprint);
+
+       goto out;
+
+intr:
+       arm_intr_disestablish(sc->sc_ih);
+       sc->sc_ih = NULL;
+hmem:
+       bus_space_unmap(sc->sc_iot, sc->ph_ioh, hmem.size);
+pmem:
+       bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
+       sc->sc_size = 0;
+out:
+       return;
+}
+
+int
+exehci_detach(struct device *self, int flags)
+{
+       struct exehci_softc             *sc = (struct exehci_softc *)self;
+       int                              rv = 0;
+
+       rv = ehci_detach(self, flags);
+       if (rv)
+               return (rv);
+
+       if (sc->sc_ih != NULL) {
+               arm_intr_disestablish(sc->sc_ih);
+               sc->sc_ih = NULL;
+       }
+
+       if (sc->sc_size) {
+               bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
+               sc->sc_size = 0;
+       }
+
+       return 0;
+}
+
+void
+exehci_setup(struct exehci_softc *sc)
+{
+       uint32_t val;
+
+       /* VBUS, GPIO_X11, only on SMDK5250 and Chromebooks */
+       exgpio_set_dir(0xa9, EXGPIO_DIR_OUT);
+       exgpio_set_bit(0xa9);
+       delay(3000);
+
+       exsysreg_usbhost_mode(1);
+       expower_usbhost_phy_ctrl(1);
+
+       delay(10000);
+
+       /* Setting up host and device simultaneously */
+       val = bus_space_read_4(sc->sc_iot, sc->ph_ioh, USBPHY_CTRL0);
+       val &= ~(HOST_CTRL0_FSEL_MASK |
+                HOST_CTRL0_COMMONON_N |
+                /* HOST Phy setting */
+                HOST_CTRL0_PHYSWRST |
+                HOST_CTRL0_PHYSWRSTALL |
+                HOST_CTRL0_SIDDQ |
+                HOST_CTRL0_FORCESUSPEND |
+                HOST_CTRL0_FORCESLEEP);
+       val |= (/* Setting up the ref freq */
+                CLK_24MHZ << 16 |
+                /* HOST Phy setting */
+                HOST_CTRL0_LINKSWRST |
+                HOST_CTRL0_UTMISWRST);
+       bus_space_write_4(sc->sc_iot, sc->ph_ioh, USBPHY_CTRL0, val);
+       delay(10000);
+       bus_space_write_4(sc->sc_iot, sc->ph_ioh, USBPHY_CTRL0,
+           bus_space_read_4(sc->sc_iot, sc->ph_ioh, USBPHY_CTRL0) &
+               ~(HOST_CTRL0_LINKSWRST | HOST_CTRL0_UTMISWRST));
+       delay(20000);
+
+       /* EHCI Ctrl setting */
+       bus_space_write_4(sc->sc_iot, sc->ph_ioh, EHCI_CTRL,
+           bus_space_read_4(sc->sc_iot, sc->ph_ioh, EHCI_CTRL) |
+               EHCI_CTRL_ENAINCRXALIGN |
+               EHCI_CTRL_ENAINCR4 |
+               EHCI_CTRL_ENAINCR8 |
+               EHCI_CTRL_ENAINCR16);
+
+       /* HSIC USB Hub initialization. */
+       if (1) {
+               exgpio_set_dir(0xc8, EXGPIO_DIR_OUT);
+               exgpio_clear_bit(0xc8);
+               delay(1000);
+               exgpio_set_bit(0xc8);
+               delay(5000);
+
+               val = bus_space_read_4(sc->sc_iot, sc->ph_ioh, HSICPHY_CTRL1);
+               val &= ~(HOST_CTRL0_SIDDQ |
+                        HOST_CTRL0_FORCESLEEP |
+                        HOST_CTRL0_FORCESUSPEND);
+               bus_space_write_4(sc->sc_iot, sc->ph_ioh, HSICPHY_CTRL1, val);
+               val |= HOST_CTRL0_PHYSWRST;
+               bus_space_write_4(sc->sc_iot, sc->ph_ioh, HSICPHY_CTRL1, val);
+               delay(1000);
+               val &= ~HOST_CTRL0_PHYSWRST;
+               bus_space_write_4(sc->sc_iot, sc->ph_ioh, HSICPHY_CTRL1, val);
+       }
+
+       /* PHY clock and power setup time */
+       delay(50000);
+}
+
+int    ehci_ex_match(struct device *, void *, void *);
+void   ehci_ex_attach(struct device *, struct device *, void *);
+
+struct cfattach ehci_ex_ca = {
+       sizeof (struct ehci_softc), ehci_ex_match, ehci_ex_attach
+};
+
+int
+ehci_ex_match(struct device *parent, void *v, void *aux)
+{
+       return 1;
+}
+
+void
+ehci_ex_attach(struct device *parent, struct device *self, void *aux)
+{
+}
diff --git a/sys/arch/armv7/exynos/exesdhc.c b/sys/arch/armv7/exynos/exesdhc.c
new file mode 100644 (file)
index 0000000..2a48896
--- /dev/null
@@ -0,0 +1,990 @@
+/*     $OpenBSD: exesdhc.c,v 1.1 2015/01/26 02:48:24 bmercer Exp $     */
+/*
+ * Copyright (c) 2009 Dale Rahn <drahn@openbsd.org>
+ * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* i.MX SD/MMC support derived from /sys/dev/sdmmc/sdhc.c */
+
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <dev/sdmmc/sdmmcchip.h>
+#include <dev/sdmmc/sdmmcvar.h>
+
+#include <armv7/armv7/armv7var.h>
+#include <armv7/exynos/exclockvar.h>
+#include <armv7/exynos/exgpiovar.h>
+
+/* registers */
+#define SDHC_DS_ADDR                   0x00
+#define SDHC_BLK_ATT                   0x04
+#define SDHC_CMD_ARG                   0x08
+#define SDHC_CMD_XFR_TYP               0x0c
+#define SDHC_CMD_RSP0                  0x10
+#define SDHC_CMD_RSP1                  0x14
+#define SDHC_CMD_RSP2                  0x18
+#define SDHC_CMD_RSP3                  0x1c
+#define SDHC_DATA_BUFF_ACC_PORT                0x20
+#define SDHC_PRES_STATE                        0x24
+#define SDHC_PROT_CTRL                 0x28
+#define SDHC_SYS_CTRL                  0x2c
+#define SDHC_INT_STATUS                        0x30
+#define SDHC_INT_STATUS_EN             0x34
+#define SDHC_INT_SIGNAL_EN             0x38
+#define SDHC_AUTOCMD12_ERR_STATUS      0x3c
+#define SDHC_HOST_CTRL_CAP             0x40
+#define SDHC_WTMK_LVL                  0x44
+#define SDHC_MIX_CTRL                  0x48
+#define SDHC_FORCE_EVENT               0x50
+#define SDHC_ADMA_ERR_STATUS           0x54
+#define SDHC_ADMA_SYS_ADDR             0x58
+#define SDHC_DLL_CTRL                  0x60
+#define SDHC_DLL_STATUS                        0x64
+#define SDHC_CLK_TUNE_CTRL_STATUS      0x68
+#define SDHC_VEND_SPEC                 0xc0
+#define SDHC_MMC_BOOT                  0xc4
+#define SDHC_VEND_SPEC2                        0xc8
+#define SDHC_HOST_CTRL_VER             0xfc
+
+/* bits and bytes */
+#define SDHC_BLK_ATT_BLKCNT_MAX                        0xffff
+#define SDHC_BLK_ATT_BLKCNT_SHIFT              16
+#define SDHC_BLK_ATT_BLKSIZE_SHIFT             0
+#define SDHC_CMD_XFR_TYP_CMDINDX_SHIFT         24
+#define SDHC_CMD_XFR_TYP_CMDINDX_SHIFT_MASK    (0x3f << SDHC_CMD_XFR_TYP_CMDINDX_SHIFT)
+#define SDHC_CMD_XFR_TYP_CMDTYP_SHIFT          22
+#define SDHC_CMD_XFR_TYP_DPSEL_SHIFT           21
+#define SDHC_CMD_XFR_TYP_DPSEL                 (1 << SDHC_CMD_XFR_TYP_DPSEL_SHIFT)
+#define SDHC_CMD_XFR_TYP_CICEN_SHIFT           20
+#define SDHC_CMD_XFR_TYP_CICEN                 (1 << SDHC_CMD_XFR_TYP_CICEN_SHIFT)
+#define SDHC_CMD_XFR_TYP_CCCEN_SHIFT           19
+#define SDHC_CMD_XFR_TYP_CCCEN                 (1 << SDHC_CMD_XFR_TYP_CCCEN_SHIFT)
+#define SDHC_CMD_XFR_TYP_RSPTYP_SHIFT          16
+#define SDHC_CMD_XFR_TYP_RSP_NONE              (0x0 << SDHC_CMD_XFR_TYP_RSPTYP_SHIFT)
+#define SDHC_CMD_XFR_TYP_RSP136                        (0x1 << SDHC_CMD_XFR_TYP_RSPTYP_SHIFT)
+#define SDHC_CMD_XFR_TYP_RSP48                 (0x2 << SDHC_CMD_XFR_TYP_RSPTYP_SHIFT)
+#define SDHC_CMD_XFR_TYP_RSP48B                        (0x3 << SDHC_CMD_XFR_TYP_RSPTYP_SHIFT)
+#define SDHC_PRES_STATE_WPSPL                  (1 << 19)
+#define SDHC_PRES_STATE_BREN                   (1 << 11)
+#define SDHC_PRES_STATE_BWEN                   (1 << 10)
+#define SDHC_PRES_STATE_SDSTB                  (1 << 3)
+#define SDHC_PRES_STATE_DLA                    (1 << 2)
+#define SDHC_PRES_STATE_CDIHB                  (1 << 1)
+#define SDHC_PRES_STATE_CIHB                   (1 << 0)
+#define SDHC_SYS_CTRL_RSTA                     (1 << 24)
+#define SDHC_SYS_CTRL_RSTC                     (1 << 25)
+#define SDHC_SYS_CTRL_RSTD                     (1 << 26)
+#define SDHC_SYS_CTRL_CLOCK_MASK               (0xfff << 4)
+#define SDHC_SYS_CTRL_CLOCK_DIV_SHIFT          4
+#define SDHC_SYS_CTRL_CLOCK_PRE_SHIFT          8
+#define SDHC_SYS_CTRL_DTOCV_SHIFT              16
+#define SDHC_INT_STATUS_CC                     (1 << 0)
+#define SDHC_INT_STATUS_TC                     (1 << 1)
+#define SDHC_INT_STATUS_BGE                    (1 << 2)
+#define SDHC_INT_STATUS_DINT                   (1 << 3)
+#define SDHC_INT_STATUS_BWR                    (1 << 4)
+#define SDHC_INT_STATUS_BRR                    (1 << 5)
+#define SDHC_INT_STATUS_CINS                   (1 << 6)
+#define SDHC_INT_STATUS_CRM                    (1 << 7)
+#define SDHC_INT_STATUS_CINT                   (1 << 8)
+#define SDHC_INT_STATUS_CTOE                   (1 << 16)
+#define SDHC_INT_STATUS_CCE                    (1 << 17)
+#define SDHC_INT_STATUS_CEBE                   (1 << 18)
+#define SDHC_INT_STATUS_CIC                    (1 << 19)
+#define SDHC_INT_STATUS_DTOE                   (1 << 20)
+#define SDHC_INT_STATUS_DCE                    (1 << 21)
+#define SDHC_INT_STATUS_DEBE                   (1 << 22)
+#define SDHC_INT_STATUS_DMAE                   (1 << 28)
+#define SDHC_INT_STATUS_CMD_ERR                        (SDHC_INT_STATUS_CIC | SDHC_INT_STATUS_CEBE | SDHC_INT_STATUS_CCE)
+#define SDHC_INT_STATUS_ERR                    (SDHC_INT_STATUS_CTOE | SDHC_INT_STATUS_CCE | SDHC_INT_STATUS_CEBE | \
+                                                SDHC_INT_STATUS_CIC | SDHC_INT_STATUS_DTOE | SDHC_INT_STATUS_DCE | \
+                                                SDHC_INT_STATUS_DEBE | SDHC_INT_STATUS_DMAE)
+#define SDHC_MIX_CTRL_DMAEN                    (1 << 0)
+#define SDHC_MIX_CTRL_BCEN                     (1 << 1)
+#define SDHC_MIX_CTRL_AC12EN                   (1 << 2)
+#define SDHC_MIX_CTRL_DTDSEL                   (1 << 4)
+#define SDHC_MIX_CTRL_MSBSEL                   (1 << 5)
+#define SDHC_PROT_CTRL_DMASEL_SDMA_MASK                (0x3 << 8)
+#define SDHC_HOST_CTRL_CAP_MBL_SHIFT           16
+#define SDHC_HOST_CTRL_CAP_MBL_MASK            0x7
+#define SDHC_HOST_CTRL_CAP_VS33                        (1 << 24)
+#define SDHC_HOST_CTRL_CAP_VS30                        (1 << 25)
+#define SDHC_HOST_CTRL_CAP_VS18                        (1 << 26)
+#define SDHC_VEND_SPEC_FRC_SDCLK_ON            (1 << 8)
+#define SDHC_WTMK_LVL_RD_WML_SHIFT             0
+#define SDHC_WTMK_LVL_WR_WML_SHIFT             16
+
+#define SDHC_COMMAND_TIMEOUT   hz
+#define SDHC_BUFFER_TIMEOUT    hz
+#define SDHC_TRANSFER_TIMEOUT  hz
+
+int exesdhc_match(struct device *parent, void *v, void *aux);
+void exesdhc_attach(struct device *parent, struct device *self, void *args);
+
+#include <machine/bus.h>
+
+struct exesdhc_softc {
+       struct device sc_dev;
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh;
+       void                    *sc_ih; /* Interrupt handler */
+       u_int sc_flags;
+
+       int unit;                       /* unit id */
+       struct device *sdmmc;           /* generic SD/MMC device */
+       int clockbit;                   /* clock control bit */
+       u_int clkbase;                  /* base clock frequency in KHz */
+       int maxblklen;                  /* maximum block length */
+       int flags;                      /* flags for this host */
+       uint32_t ocr;                   /* OCR value from capabilities */
+//     u_int8_t regs[14];              /* host controller state */
+       uint32_t intr_status;           /* soft interrupt status */
+       uint32_t intr_error_status;     /*  */
+};
+
+
+/* Host controller functions called by the attachment driver. */
+int    exesdhc_host_found(struct exesdhc_softc *, bus_space_tag_t,
+           bus_space_handle_t, bus_size_t, int);
+void   exesdhc_power(int, void *);
+void   exesdhc_shutdown(void *);
+int    exesdhc_intr(void *);
+
+/* RESET MODES */
+#define MMC_RESET_DAT  1
+#define MMC_RESET_CMD  2
+#define MMC_RESET_ALL  (MMC_RESET_CMD|MMC_RESET_DAT)
+
+#define HDEVNAME(sc)   ((sc)->sc_dev.dv_xname)
+
+/* flag values */
+#define SHF_USE_DMA            0x0001
+
+/* SDHC should only be accessed with 4 byte reads or writes. */
+#define HREAD4(sc, reg)                                                        \
+       (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
+#define HWRITE4(sc, reg, val)                                          \
+       bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+#define HSET4(sc, reg, bits)                                           \
+       HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
+#define HCLR4(sc, reg, bits)                                           \
+       HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
+
+int    exesdhc_host_reset(sdmmc_chipset_handle_t);
+uint32_t exesdhc_host_ocr(sdmmc_chipset_handle_t);
+int    exesdhc_host_maxblklen(sdmmc_chipset_handle_t);
+int    exesdhc_card_detect(sdmmc_chipset_handle_t);
+int    exesdhc_bus_power(sdmmc_chipset_handle_t, uint32_t);
+int    exesdhc_bus_clock(sdmmc_chipset_handle_t, int);
+void   exesdhc_card_intr_mask(sdmmc_chipset_handle_t, int);
+void   exesdhc_card_intr_ack(sdmmc_chipset_handle_t);
+void   exesdhc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *);
+int    exesdhc_start_command(struct exesdhc_softc *, struct sdmmc_command *);
+int    exesdhc_wait_state(struct exesdhc_softc *, uint32_t, uint32_t);
+int    exesdhc_soft_reset(struct exesdhc_softc *, int);
+int    exesdhc_wait_intr(struct exesdhc_softc *, int, int);
+void   exesdhc_transfer_data(struct exesdhc_softc *, struct sdmmc_command *);
+void   exesdhc_read_data(struct exesdhc_softc *, u_char *, int);
+void   exesdhc_write_data(struct exesdhc_softc *, u_char *, int);
+
+//#define SDHC_DEBUG
+#ifdef SDHC_DEBUG
+int exesdhcdebug = 20;
+#define DPRINTF(n,s)   do { if ((n) <= exesdhcdebug) printf s; } while (0)
+#else
+#define DPRINTF(n,s)   do {} while(0)
+#endif
+
+struct sdmmc_chip_functions exesdhc_functions = {
+       /* host controller reset */
+       exesdhc_host_reset,
+       /* host controller capabilities */
+       exesdhc_host_ocr,
+       exesdhc_host_maxblklen,
+       /* card detection */
+       exesdhc_card_detect,
+       /* bus power and clock frequency */
+       exesdhc_bus_power,
+       exesdhc_bus_clock,
+       /* command execution */
+       exesdhc_exec_command,
+       /* card interrupt */
+       exesdhc_card_intr_mask,
+       exesdhc_card_intr_ack
+};
+
+struct cfdriver exesdhc_cd = {
+       NULL, "exesdhc", DV_DULL
+};
+
+struct cfattach exesdhc_ca = {
+       sizeof(struct exesdhc_softc), NULL, exesdhc_attach
+};
+struct cfattach exesdhc_fdt_ca = {
+       sizeof(struct exesdhc_softc), exesdhc_match, exesdhc_attach
+};
+
+int
+exesdhc_match(struct device *parent, void *v, void *aux)
+{
+       struct armv7_attach_args *aa = aux;
+
+       if (fdt_node_compatible("samsung,exynos5250-dw-mshc", aa->aa_node))
+               return 1;
+
+       return 0;
+}
+
+void
+exesdhc_attach(struct device *parent, struct device *self, void *args)
+{
+       struct exesdhc_softc            *sc = (struct exesdhc_softc *) self;
+       struct armv7_attach_args        *aa = args;
+       struct fdt_memory                mem;
+       struct sdmmcbus_attach_args      saa;
+       int                              error = 1, irq;
+       uint32_t                         caps;
+
+       sc->sc_iot = aa->aa_iot;
+       if (aa->aa_node) {
+               static int unit = 0;
+               uint32_t ints[3];
+
+               sc->unit = unit++;
+
+               if (fdt_get_memory_address(aa->aa_node, 0, &mem))
+                       panic("%s: could not extract memory data from FDT",
+                           __func__);
+
+               /* TODO: Add interrupt FDT API. */
+               if (fdt_node_property_ints(aa->aa_node, "interrupts",
+                   ints, 3) != 3)
+                       panic("%s: could not extract interrupt data from FDT",
+                           __func__);
+
+               irq = ints[1];
+       } else {
+               irq = aa->aa_dev->irq[0];
+               mem.addr = aa->aa_dev->mem[0].addr;
+               mem.size = aa->aa_dev->mem[0].size;
+       }
+
+       if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh))
+               panic("%s: bus_space_map failed!", __func__);
+
+       printf("\n");
+
+       /* XXX DMA channels? */
+
+       sc->sc_ih = arm_intr_establish(irq, IPL_SDMMC,
+           exesdhc_intr, sc, sc->sc_dev.dv_xname);
+
+       /*
+        * Reset the host controller and enable interrupts.
+        */
+       if (exesdhc_host_reset(sc))
+               goto err;
+
+       /* Determine host capabilities. */
+       caps = HREAD4(sc, SDHC_HOST_CTRL_CAP);
+
+       /*
+        * Determine the base clock frequency. (2.2.24)
+        */
+       //sc->clkbase = exccm_get_usdhx(aa->aa_dev->unit + 1);
+       sc->clkbase = 0;
+
+       /*
+        * Determine SD bus voltage levels supported by the controller.
+        */
+       if (caps & SDHC_HOST_CTRL_CAP_VS18)
+               SET(sc->ocr, MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V);
+       if (caps & SDHC_HOST_CTRL_CAP_VS30)
+               SET(sc->ocr, MMC_OCR_2_9V_3_0V | MMC_OCR_3_0V_3_1V);
+       if (caps & SDHC_HOST_CTRL_CAP_VS33)
+               SET(sc->ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V);
+
+       /*
+        * Determine max block size.
+        */
+       switch ((caps >> SDHC_HOST_CTRL_CAP_MBL_SHIFT)
+           & SDHC_HOST_CTRL_CAP_MBL_MASK) {
+       case 0:
+               sc->maxblklen = 512;
+               break;
+       case 1:
+               sc->maxblklen = 1024;
+               break;
+       case 2:
+               sc->maxblklen = 2048;
+               break;
+       case 3:
+               sc->maxblklen = 4096;
+               break;
+       default:
+               sc->maxblklen = 512;
+               printf("invalid capability blocksize in capa %08x,"
+                   " trying 512\n", caps);
+       }
+
+       /* somewhere this blksize might be used instead of the device's */
+       sc->maxblklen = 512;
+
+       /*
+        * Attach the generic SD/MMC bus driver.  (The bus driver must
+        * not invoke any chipset functions before it is attached.)
+        */
+
+       bzero(&saa, sizeof(saa));
+       saa.saa_busname = "sdmmc";
+       saa.sct = &exesdhc_functions;
+       saa.sch = sc;
+
+       sc->sdmmc = config_found(&sc->sc_dev, &saa, NULL);
+       if (sc->sdmmc == NULL) {
+               error = 0;
+               goto err;
+       }
+       
+       return;
+
+err:
+       return;
+}
+
+
+/*
+ * Power hook established by or called from attachment driver.
+ */
+void
+exesdhc_power(int why, void *arg)
+{
+}
+
+/*
+ * Shutdown hook established by or called from attachment driver.
+ */
+void
+exesdhc_shutdown(void *arg)
+{
+       struct exesdhc_softc *sc = arg;
+
+       /* XXX chip locks up if we don't disable it before reboot. */
+       (void)exesdhc_host_reset(sc);
+}
+
+/*
+ * Reset the host controller.  Called during initialization, when
+ * cards are removed, upon resume, and during error recovery.
+ */
+int
+exesdhc_host_reset(sdmmc_chipset_handle_t sch)
+{
+       struct exesdhc_softc *sc = sch;
+       u_int32_t imask;
+       int error;
+       int s;
+
+       s = splsdmmc();
+
+       /* Disable all interrupts. */
+       HWRITE4(sc, SDHC_INT_STATUS_EN, 0);
+       HWRITE4(sc, SDHC_INT_SIGNAL_EN, 0);
+
+       /*
+        * Reset the entire host controller and wait up to 100ms for
+        * the controller to clear the reset bit.
+        */
+       if ((error = exesdhc_soft_reset(sc, SDHC_SYS_CTRL_RSTA)) != 0) {
+               splx(s);
+               return (error);
+       }
+
+       /* Set data timeout counter value to max for now. */
+       HSET4(sc, SDHC_SYS_CTRL, 0xe << SDHC_SYS_CTRL_DTOCV_SHIFT);
+
+       /* Enable interrupts. */
+       imask = SDHC_INT_STATUS_CC | SDHC_INT_STATUS_TC |
+           SDHC_INT_STATUS_BGE |
+#ifdef SDHC_DMA
+           SHDC_INT_STATUS_DINT;
+#else
+           SDHC_INT_STATUS_BRR | SDHC_INT_STATUS_BWR;
+#endif
+
+       imask |= SDHC_INT_STATUS_CTOE | SDHC_INT_STATUS_CCE |
+           SDHC_INT_STATUS_CEBE | SDHC_INT_STATUS_CIC |
+           SDHC_INT_STATUS_DTOE | SDHC_INT_STATUS_DCE |
+           SDHC_INT_STATUS_DEBE | SDHC_INT_STATUS_DMAE;
+
+       HWRITE4(sc, SDHC_INT_STATUS_EN, imask);
+       HWRITE4(sc, SDHC_INT_SIGNAL_EN, imask);
+
+       // Use no or simple DMA
+       HWRITE4(sc, SDHC_PROT_CTRL,
+           HREAD4(sc, SDHC_PROT_CTRL) & ~SDHC_PROT_CTRL_DMASEL_SDMA_MASK);
+
+       splx(s);
+       return 0;
+}
+
+uint32_t
+exesdhc_host_ocr(sdmmc_chipset_handle_t sch)
+{
+       struct exesdhc_softc *sc = sch;
+       return sc->ocr;
+}
+
+int
+exesdhc_host_maxblklen(sdmmc_chipset_handle_t sch)
+{
+       struct exesdhc_softc *sc = sch;
+       return sc->maxblklen;
+}
+
+/*
+ * Return non-zero if the card is currently inserted.
+ */
+int
+exesdhc_card_detect(sdmmc_chipset_handle_t sch)
+{
+       struct exesdhc_softc *sc = sch;
+       int gpio;
+
+       switch (board_id)
+       {
+       case BOARD_ID_EXYNOS5_CHROMEBOOK:
+               switch (sc->unit) {
+                       case 2:
+                               gpio = 6*32 + 0;
+                               break;
+                       case 3:
+                               gpio = 1*32 + 6;
+                               break;
+                       default:
+                               return 0;
+               }
+               return exgpio_get_bit(gpio) ? 0 : 1;
+       default:
+               return 1;
+       }
+}
+
+/*
+ * Set or change SD bus voltage and enable or disable SD bus power.
+ * Return zero on success.
+ */
+int
+exesdhc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
+{
+       return 0;
+}
+
+/*
+ * Set or change SDCLK frequency or disable the SD clock.
+ * Return zero on success.
+ */
+int
+exesdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq)
+{
+       struct exesdhc_softc *sc = sch;
+       int div, pre_div, cur_freq, s;
+       int error = 0;
+
+       s = splsdmmc();
+
+       if (sc->clkbase / 16 > freq) {
+               for (pre_div = 2; pre_div < 256; pre_div *= 2)
+                       if ((sc->clkbase / pre_div) <= (freq * 16))
+                               break;
+       } else
+               pre_div = 2;
+
+       if (sc->clkbase == freq)
+               pre_div = 1;
+
+       for (div = 1; div <= 16; div++)
+               if ((sc->clkbase / (div * pre_div)) <= freq)
+                       break;
+
+       div -= 1;
+       pre_div >>= 1;
+
+       cur_freq = sc->clkbase / (pre_div * 2) / (div + 1);
+
+       /* disable force CLK ouput active */
+       HCLR4(sc, SDHC_VEND_SPEC, SDHC_VEND_SPEC_FRC_SDCLK_ON);
+
+       /* wait while clock is unstable */
+       if ((error = exesdhc_wait_state(sc, SDHC_PRES_STATE_SDSTB, SDHC_PRES_STATE_SDSTB)) != 0)
+               goto ret;
+
+       HCLR4(sc, SDHC_SYS_CTRL, SDHC_SYS_CTRL_CLOCK_MASK);
+       HSET4(sc, SDHC_SYS_CTRL, (div << SDHC_SYS_CTRL_CLOCK_DIV_SHIFT) | (pre_div << SDHC_SYS_CTRL_CLOCK_PRE_SHIFT));
+
+       /* wait while clock is unstable */
+       if ((error = exesdhc_wait_state(sc, SDHC_PRES_STATE_SDSTB, SDHC_PRES_STATE_SDSTB)) != 0)
+               goto ret;
+
+ret:
+       splx(s);
+       return error;
+}
+
+void
+exesdhc_card_intr_mask(sdmmc_chipset_handle_t sch, int enable)
+{
+       printf("exesdhc_card_intr_mask\n");
+       /* - this is SDIO card interrupt */
+       struct exesdhc_softc *sc = sch;
+
+       if (enable) {
+               HSET4(sc, SDHC_INT_STATUS_EN, SDHC_INT_STATUS_CINT);
+               HSET4(sc, SDHC_INT_SIGNAL_EN, SDHC_INT_STATUS_CINT);
+       } else {
+               HCLR4(sc, SDHC_INT_STATUS_EN, SDHC_INT_STATUS_CINT);
+               HCLR4(sc, SDHC_INT_SIGNAL_EN, SDHC_INT_STATUS_CINT);
+       }
+}
+
+void
+exesdhc_card_intr_ack(sdmmc_chipset_handle_t sch)
+{
+       printf("exesdhc_card_intr_ack\n");
+       struct exesdhc_softc *sc = sch;
+
+       HWRITE4(sc, SDHC_INT_STATUS, SDHC_INT_STATUS_CINT);
+}
+
+int
+exesdhc_wait_state(struct exesdhc_softc *sc, uint32_t mask, uint32_t value)
+{
+       uint32_t state;
+       int timeout;
+       state = HREAD4(sc, SDHC_PRES_STATE);
+       DPRINTF(3,("%s: wait_state %x %x %x)\n", HDEVNAME(sc),
+           mask, value, state));
+       for (timeout = 1000; timeout > 0; timeout--) {
+               if (((state = HREAD4(sc, SDHC_PRES_STATE)) & mask) == value)
+                       return 0;
+               delay(10);
+       }
+       DPRINTF(0,("%s: timeout waiting for %x\n", HDEVNAME(sc),
+           value, state));
+       return ETIMEDOUT;
+}
+
+void
+exesdhc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
+{
+       struct exesdhc_softc *sc = sch;
+       int error;
+
+       /*
+        * Start the command, or mark `cmd' as failed and return.
+        */
+       error = exesdhc_start_command(sc, cmd);
+       if (error != 0) {
+               cmd->c_error = error;
+               SET(cmd->c_flags, SCF_ITSDONE);
+               return;
+       }
+
+       /*
+        * Wait until the command phase is done, or until the command
+        * is marked done for any other reason.
+        */
+       if (!exesdhc_wait_intr(sc, SDHC_INT_STATUS_CC, SDHC_COMMAND_TIMEOUT)) {
+               cmd->c_error = ETIMEDOUT;
+               SET(cmd->c_flags, SCF_ITSDONE);
+               return;
+       }
+
+       /*
+        * The host controller removes bits [0:7] from the response
+        * data (CRC) and we pass the data up unchanged to the bus
+        * driver (without padding).
+        */
+       if (cmd->c_error == 0 && ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
+               if (ISSET(cmd->c_flags, SCF_RSP_136)) {
+                       cmd->c_resp[0] = HREAD4(sc, SDHC_CMD_RSP0);
+                       cmd->c_resp[1] = HREAD4(sc, SDHC_CMD_RSP1);
+                       cmd->c_resp[2] = HREAD4(sc, SDHC_CMD_RSP2);
+                       cmd->c_resp[3] = HREAD4(sc, SDHC_CMD_RSP3);
+
+#ifdef SDHC_DEBUG
+                       printf("resp[0] 0x%08x\nresp[1] 0x%08x\nresp[2] 0x%08x\nresp[3] 0x%08x\n", cmd->c_resp[0], cmd->c_resp[1], cmd->c_resp[2], cmd->c_resp[3]);
+#endif
+               } else  {
+                       cmd->c_resp[0] = HREAD4(sc, SDHC_CMD_RSP0);
+#ifdef SDHC_DEBUG
+                       printf("resp[0] 0x%08x\n", cmd->c_resp[0]);
+#endif
+               }
+       }
+
+       /*
+        * If the command has data to transfer in any direction,
+        * execute the transfer now.
+        */
+       if (cmd->c_error == 0 && cmd->c_data)
+               exesdhc_transfer_data(sc, cmd);
+
+       DPRINTF(1,("%s: cmd %u done (flags=%#x error=%d)\n",
+           HDEVNAME(sc), cmd->c_opcode, cmd->c_flags, cmd->c_error));
+       SET(cmd->c_flags, SCF_ITSDONE);
+}
+
+int
+exesdhc_start_command(struct exesdhc_softc *sc, struct sdmmc_command *cmd)
+{
+       u_int32_t blksize = 0;
+       u_int32_t blkcount = 0;
+       u_int32_t command;
+       int error;
+       int s;
+
+       DPRINTF(1,("%s: start cmd %u arg=%#x data=%#x dlen=%d flags=%#x "
+           "proc=\"%s\"\n", HDEVNAME(sc), cmd->c_opcode, cmd->c_arg,
+           cmd->c_data, cmd->c_datalen, cmd->c_flags, curproc ?
+           curproc->p_comm : ""));
+
+       /*
+        * The maximum block length for commands should be the minimum
+        * of the host buffer size and the card buffer size. (1.7.2)
+        */
+
+       /* Fragment the data into proper blocks. */
+       if (cmd->c_datalen > 0) {
+               blksize = MIN(cmd->c_datalen, cmd->c_blklen);
+               blkcount = cmd->c_datalen / blksize;
+               if (cmd->c_datalen % blksize > 0) {
+                       /* XXX: Split this command. (1.7.4) */
+                       printf("%s: data not a multiple of %d bytes\n",
+                           HDEVNAME(sc), blksize);
+                       return EINVAL;
+               }
+       }
+
+       /* Check limit imposed by 9-bit block count. (1.7.2) */
+       if (blkcount > SDHC_BLK_ATT_BLKCNT_MAX) {
+               printf("%s: too much data\n", HDEVNAME(sc));
+               return EINVAL;
+       }
+
+       /* setup for PIO, check for write protection */
+       if (!ISSET(cmd->c_flags, SCF_CMD_READ)) {
+               if (!(HREAD4(sc, SDHC_PRES_STATE) & SDHC_PRES_STATE_WPSPL)) {
+                       printf("%s: card is write protected\n",
+                           HDEVNAME(sc));
+                       return EINVAL;
+               }
+       }
+
+#ifdef SDHC_DMA
+       /* set watermark level */
+       uint32_t wml = blksize / sizeof(uint32_t);
+       if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
+               if (wml > 16)
+                       wml = 16;
+               HWRITE4(sc, SDHC_WTMK_LVL, wml << SDHC_WTMK_LVL_RD_WML_SHIFT);
+       } else {
+               if (wml > 128)
+                       wml = 128;
+               HWRITE4(sc, SDHC_WTMK_LVL, wml << SDHC_WTMK_LVL_WR_WML_SHIFT);
+       }
+#endif
+
+       /* Prepare transfer mode register value. (2.2.5) */
+       command = 0;
+
+       if (ISSET(cmd->c_flags, SCF_CMD_READ))
+               command |= SDHC_MIX_CTRL_DTDSEL;
+       if (blkcount > 0) {
+               command |= SDHC_MIX_CTRL_BCEN;
+#ifdef SDHC_DMA
+               command |= SDHC_MIX_CTRL_DMAEN;
+#endif
+               if (blkcount > 1) {
+                       command |= SDHC_MIX_CTRL_MSBSEL;
+                       command |= SDHC_MIX_CTRL_AC12EN;
+               }
+       }
+
+       command |= (cmd->c_opcode << SDHC_CMD_XFR_TYP_CMDINDX_SHIFT) &
+          SDHC_CMD_XFR_TYP_CMDINDX_SHIFT_MASK;
+
+       if (ISSET(cmd->c_flags, SCF_RSP_CRC))
+               command |= SDHC_CMD_XFR_TYP_CCCEN;
+       if (ISSET(cmd->c_flags, SCF_RSP_IDX))
+               command |= SDHC_CMD_XFR_TYP_CICEN;
+       if (cmd->c_data != NULL)
+               command |= SDHC_CMD_XFR_TYP_DPSEL;
+
+       if (!ISSET(cmd->c_flags, SCF_RSP_PRESENT))
+               command |= SDHC_CMD_XFR_TYP_RSP_NONE;
+       else if (ISSET(cmd->c_flags, SCF_RSP_136))
+               command |= SDHC_CMD_XFR_TYP_RSP136;
+       else if (ISSET(cmd->c_flags, SCF_RSP_BSY))
+               command |= SDHC_CMD_XFR_TYP_RSP48B;
+       else
+               command |= SDHC_CMD_XFR_TYP_RSP48;
+
+       /* Wait until command and data inhibit bits are clear. (1.5) */
+       if ((error = exesdhc_wait_state(sc, SDHC_PRES_STATE_CIHB, 0)) != 0)
+               return error;
+
+       s = splsdmmc();
+
+       /*
+        * Start a CPU data transfer.  Writing to the high order byte
+        * of the SDHC_COMMAND register triggers the SD command. (1.5)
+        */
+#ifdef SDHC_DMA
+       if (cmd->c_data)
+               HWRITE4(sc, SDHC_DS_ADDR, (uint32_t)cmd->c_data);
+#endif
+       HWRITE4(sc, SDHC_BLK_ATT, blkcount << SDHC_BLK_ATT_BLKCNT_SHIFT |
+           blksize << SDHC_BLK_ATT_BLKSIZE_SHIFT);
+       HWRITE4(sc, SDHC_CMD_ARG, cmd->c_arg);
+       HWRITE4(sc, SDHC_MIX_CTRL,
+           (HREAD4(sc, SDHC_MIX_CTRL) & (0xf << 22)) | (command & 0xffff));
+       HWRITE4(sc, SDHC_CMD_XFR_TYP, command);
+
+       splx(s);
+       return 0;
+}
+
+void
+exesdhc_transfer_data(struct exesdhc_softc *sc, struct sdmmc_command *cmd)
+{
+#ifndef SDHC_DMA
+       u_char *datap = cmd->c_data;
+       int i;
+#endif
+       int datalen;
+       int mask;
+       int error;
+
+       mask = ISSET(cmd->c_flags, SCF_CMD_READ) ?
+           SDHC_PRES_STATE_BREN : SDHC_PRES_STATE_BWEN;
+       error = 0;
+       datalen = cmd->c_datalen;
+
+       DPRINTF(1,("%s: resp=%#x datalen=%d\n", HDEVNAME(sc),
+           MMC_R1(cmd->c_resp), datalen));
+
+#ifndef SDHC_DMA
+       while (datalen > 0) {
+               if (!exesdhc_wait_intr(sc, SDHC_INT_STATUS_BRR | SDHC_INT_STATUS_BWR,
+                   SDHC_BUFFER_TIMEOUT)) {
+                       error = ETIMEDOUT;
+                       break;
+               }
+
+               if ((error = exesdhc_wait_state(sc, mask, mask)) != 0)
+                       break;
+
+               /* FIXME: wait a bit, else it fails */
+               delay(100);
+               i = MIN(datalen, cmd->c_blklen);
+               if (ISSET(cmd->c_flags, SCF_CMD_READ))
+                       exesdhc_read_data(sc, datap, i);
+               else
+                       exesdhc_write_data(sc, datap, i);
+
+               datap += i;
+               datalen -= i;
+       }
+#endif
+
+       if (error == 0 && !exesdhc_wait_intr(sc, SDHC_INT_STATUS_TC,
+           SDHC_TRANSFER_TIMEOUT))
+               error = ETIMEDOUT;
+
+       if (error != 0)
+               cmd->c_error = error;
+       SET(cmd->c_flags, SCF_ITSDONE);
+
+       DPRINTF(1,("%s: data transfer done (error=%d)\n",
+           HDEVNAME(sc), cmd->c_error));
+}
+
+void
+exesdhc_read_data(struct exesdhc_softc *sc, u_char *datap, int datalen)
+{
+       while (datalen > 3) {
+               *(uint32_t *)datap = HREAD4(sc, SDHC_DATA_BUFF_ACC_PORT);
+               datap += 4;
+               datalen -= 4;
+       }
+       if (datalen > 0) {
+               uint32_t rv = HREAD4(sc, SDHC_DATA_BUFF_ACC_PORT);
+               do {
+                       *datap++ = rv & 0xff;
+                       rv = rv >> 8;
+               } while (--datalen > 0);
+       }
+}
+
+void
+exesdhc_write_data(struct exesdhc_softc *sc, u_char *datap, int datalen)
+{
+       while (datalen > 3) {
+               DPRINTF(3,("%08x\n", *(uint32_t *)datap));
+               HWRITE4(sc, SDHC_DATA_BUFF_ACC_PORT, *((uint32_t *)datap));
+               datap += 4;
+               datalen -= 4;
+       }
+       if (datalen > 0) {
+               uint32_t rv = *datap++;
+               if (datalen > 1)
+                       rv |= *datap++ << 8;
+               if (datalen > 2)
+                       rv |= *datap++ << 16;
+               DPRINTF(3,("rv %08x\n", rv));
+               HWRITE4(sc, SDHC_DATA_BUFF_ACC_PORT, rv);
+       }
+}
+
+/* Prepare for another command. */
+int
+exesdhc_soft_reset(struct exesdhc_softc *sc, int mask)
+{
+       int timo;
+
+       DPRINTF(1,("%s: software reset reg=%#x\n", HDEVNAME(sc), mask));
+
+       /* disable force CLK ouput active */
+       HCLR4(sc, SDHC_VEND_SPEC, SDHC_VEND_SPEC_FRC_SDCLK_ON);
+
+       /* reset */
+       HSET4(sc, SDHC_SYS_CTRL, mask);
+       delay(10);
+
+       for (timo = 1000; timo > 0; timo--) {
+               if (!ISSET(HREAD4(sc, SDHC_SYS_CTRL), mask))
+                       break;
+               delay(10);
+       }
+       if (timo == 0) {
+               DPRINTF(1,("%s: timeout reg=%#x\n", HDEVNAME(sc),
+                   HREAD4(sc, SDHC_SYS_CTRL)));
+               return ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+int
+exesdhc_wait_intr(struct exesdhc_softc *sc, int mask, int timo)
+{
+       int status;
+       int s;
+
+       mask |= SDHC_INT_STATUS_ERR;
+       s = splsdmmc();
+
+       /* enable interrupts for brr and bwr */
+       if (mask & (SDHC_INT_STATUS_BRR | SDHC_INT_STATUS_BWR))
+               HSET4(sc, SDHC_INT_SIGNAL_EN, (SDHC_INT_STATUS_BRR | SDHC_INT_STATUS_BWR));
+
+       status = sc->intr_status & mask;
+       while (status == 0) {
+               if (tsleep(&sc->intr_status, PWAIT, "hcintr", timo)
+                   == EWOULDBLOCK) {
+                       status |= SDHC_INT_STATUS_ERR;
+                       break;
+               }
+               status = sc->intr_status & mask;
+       }
+       sc->intr_status &= ~status;
+       DPRINTF(2,("%s: intr status %#x error %#x\n", HDEVNAME(sc), status,
+           sc->intr_error_status));
+
+       /* Command timeout has higher priority than command complete. */
+       if (ISSET(status, SDHC_INT_STATUS_ERR)) {
+               sc->intr_error_status = 0;
+               (void)exesdhc_soft_reset(sc, SDHC_SYS_CTRL_RSTC | SDHC_SYS_CTRL_RSTD);
+               status = 0;
+       }
+
+       splx(s);
+       return status;
+}
+
+/*
+ * Established by attachment driver at interrupt priority IPL_SDMMC.
+ */
+int
+exesdhc_intr(void *arg)
+{
+       struct exesdhc_softc *sc = arg;
+
+       u_int32_t status;
+
+       /* Find out which interrupts are pending. */
+       status = HREAD4(sc, SDHC_INT_STATUS);
+
+#ifndef SDHC_DMA
+       /* disable interrupts for brr and bwr, else we get flooded */
+       if (status & (SDHC_INT_STATUS_BRR | SDHC_INT_STATUS_BWR))
+               HCLR4(sc, SDHC_INT_SIGNAL_EN, (SDHC_INT_STATUS_BRR | SDHC_INT_STATUS_BWR));
+#endif
+
+       /* Acknowledge the interrupts we are about to handle. */
+       HWRITE4(sc, SDHC_INT_STATUS, status);
+       DPRINTF(2,("%s: interrupt status=0x%08x\n", HDEVNAME(sc),
+           status, status));
+
+       /*
+        * Service error interrupts.
+        */
+       if (ISSET(status, SDHC_INT_STATUS_CMD_ERR |
+           SDHC_INT_STATUS_CTOE | SDHC_INT_STATUS_DTOE)) {
+               sc->intr_status |= status;
+               sc->intr_error_status |= status & 0xffff0000;
+               wakeup(&sc->intr_status);
+       }
+
+       /*
+        * Wake up the blocking process to service command
+        * related interrupt(s).
+        */
+       if (ISSET(status, SDHC_INT_STATUS_BRR | SDHC_INT_STATUS_BWR |
+           SDHC_INT_STATUS_TC | SDHC_INT_STATUS_CC)) {
+               sc->intr_status |= status;
+               wakeup(&sc->intr_status);
+       }
+
+       /*
+        * Service SD card interrupts.
+        */
+       if (ISSET(status, SDHC_INT_STATUS_CINT)) {
+               DPRINTF(0,("%s: card interrupt\n", HDEVNAME(sc)));
+               HCLR4(sc, SDHC_INT_STATUS, SDHC_INT_STATUS_CINT);
+               sdmmc_card_intr(sc->sdmmc);
+       }
+       return 1;
+}
diff --git a/sys/arch/armv7/exynos/exgpio.c b/sys/arch/armv7/exynos/exgpio.c
new file mode 100644 (file)
index 0000000..fa8bbf3
--- /dev/null
@@ -0,0 +1,283 @@
+/* $OpenBSD: exgpio.c,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
+/*
+ * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/evcount.h>
+
+#include <arm/cpufunc.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+#include <machine/intr.h>
+
+#include <armv7/armv7/armv7var.h>
+#include <armv7/exynos/exgpiovar.h>
+
+/* Exynos5 registers */
+#define GPIO_BANK_SIZE         0x20
+#define GPIO_BANK(x)           (GPIO_BANK_SIZE * ((x) / 8))
+#define GPIO_CON(x)            (GPIO_BANK(x) + 0x00)
+#define GPIO_DAT(x)            (GPIO_BANK(x) + 0x04)
+#define GPIO_PULL(x)           (GPIO_BANK(x) + 0x08)
+#define GPIO_DRV(x)            (GPIO_BANK(x) + 0x0c)
+#define GPIO_PDN_CON(x)                (GPIO_BANK(x) + 0x10)
+#define GPIO_PDN_PULL(x)       (GPIO_BANK(x) + 0x14)
+
+/* bits and bytes */
+#define GPIO_PIN(x)            ((x) % 8)
+#define GPIO_CON_INPUT(x)      (0x0 << (GPIO_PIN(x) << 2))
+#define GPIO_CON_OUTPUT(x)     (0x1 << (GPIO_PIN(x) << 2))
+#define GPIO_CON_IRQ(x)                (0xf << (GPIO_PIN(x) << 2))
+#define GPIO_CON_MASK(x)       (0xf << (GPIO_PIN(x) << 2))
+#define GPIO_DAT_SET(x)                (0x1 << (GPIO_PIN(x) << 0))
+#define GPIO_DAT_MASK(x)       (0x1 << (GPIO_PIN(x) << 0))
+#define GPIO_PULL_NONE(x)      (0x0 << (GPIO_PIN(x) << 1))
+#define GPIO_PULL_DOWN(x)      (0x1 << (GPIO_PIN(x) << 1))
+#define GPIO_PULL_UP(x)                (0x3 << (GPIO_PIN(x) << 1))
+#define GPIO_PULL_MASK(x)      (0x3 << (GPIO_PIN(x) << 1))
+#define GPIO_DRV_1X(x)         (0x0 << (GPIO_PIN(x) << 1))
+#define GPIO_DRV_2X(x)         (0x1 << (GPIO_PIN(x) << 1))
+#define GPIO_DRV_3X(x)         (0x2 << (GPIO_PIN(x) << 1))
+#define GPIO_DRV_4X(x)         (0x3 << (GPIO_PIN(x) << 1))
+#define GPIO_DRV_MASK(x)       (0x3 << (GPIO_PIN(x) << 1))
+
+#define GPIO_PINS_PER_BANK     8
+
+struct exgpio_softc {
+       struct device           sc_dev;
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh;
+       int                     sc_ngpio;
+       unsigned int (*sc_get_bit)(struct exgpio_softc *sc,
+           unsigned int gpio);
+       void (*sc_set_bit)(struct exgpio_softc *sc,
+           unsigned int gpio);
+       void (*sc_clear_bit)(struct exgpio_softc *sc,
+           unsigned int gpio);
+       void (*sc_set_dir)(struct exgpio_softc *sc,
+           unsigned int gpio, unsigned int dir);
+};
+
+int exgpio_match(struct device *parent, void *v, void *aux);
+void exgpio_attach(struct device *parent, struct device *self, void *args);
+
+struct exgpio_softc *exgpio_pin_to_inst(unsigned int);
+unsigned int exgpio_pin_to_offset(unsigned int);
+unsigned int exgpio_v5_get_bit(struct exgpio_softc *, unsigned int);
+void exgpio_v5_set_bit(struct exgpio_softc *, unsigned int);
+void exgpio_v5_clear_bit(struct exgpio_softc *, unsigned int);
+void exgpio_v5_set_dir(struct exgpio_softc *, unsigned int, unsigned int);
+unsigned int exgpio_v5_get_dir(struct exgpio_softc *, unsigned int);
+
+
+struct cfattach        exgpio_ca = {
+       sizeof (struct exgpio_softc), NULL, exgpio_attach
+};
+struct cfattach        exgpio_fdt_ca = {
+       sizeof (struct exgpio_softc), exgpio_match, exgpio_attach
+};
+
+struct cfdriver exgpio_cd = {
+       NULL, "exgpio", DV_DULL
+};
+
+int
+exgpio_match(struct device *parent, void *v, void *aux)
+{
+       struct armv7_attach_args *aa = aux;
+
+       if (fdt_node_compatible("samsung,exynos5250-pinctrl", aa->aa_node))
+               return 1;
+
+       return 0;
+}
+
+void
+exgpio_attach(struct device *parent, struct device *self, void *args)
+{
+       struct armv7_attach_args *aa = args;
+       struct exgpio_softc *sc = (struct exgpio_softc *) self;
+       struct fdt_memory mem;
+
+       sc->sc_iot = aa->aa_iot;
+       if (aa->aa_node) {
+               if (fdt_get_memory_address(aa->aa_node, 0, &mem))
+                       panic("%s: could not extract memory data from FDT",
+                           __func__);
+       } else {
+               mem.addr = aa->aa_dev->mem[0].addr;
+               mem.size = aa->aa_dev->mem[0].size;
+       }
+       if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh))
+               panic("%s: bus_space_map failed!", __func__);
+
+       sc->sc_ngpio = (mem.size / GPIO_BANK_SIZE) * GPIO_PINS_PER_BANK;
+
+       sc->sc_get_bit  = exgpio_v5_get_bit;
+       sc->sc_set_bit = exgpio_v5_set_bit;
+       sc->sc_clear_bit = exgpio_v5_clear_bit;
+       sc->sc_set_dir = exgpio_v5_set_dir;
+
+       printf("\n");
+
+       /* XXX - IRQ */
+       /* XXX - SYSCONFIG */
+       /* XXX - CTRL */
+       /* XXX - DEBOUNCE */
+}
+
+struct exgpio_softc *
+exgpio_pin_to_inst(unsigned int gpio)
+{
+       int i;
+
+       for (i = 0; exgpio_cd.cd_devs[i] != NULL; i++)
+       {
+               struct exgpio_softc *sc = exgpio_cd.cd_devs[i];
+               if (gpio < sc->sc_ngpio)
+                       return sc;
+               else
+                       gpio -= sc->sc_ngpio;
+       }
+
+       return NULL;
+}
+
+unsigned int
+exgpio_pin_to_offset(unsigned int gpio)
+{
+       int i;
+
+       for (i = 0; exgpio_cd.cd_devs[i] != NULL; i++)
+       {
+               struct exgpio_softc *sc = exgpio_cd.cd_devs[i];
+               if (gpio < sc->sc_ngpio)
+                       return gpio;
+               else
+                       gpio -= sc->sc_ngpio;
+       }
+
+       return 0;
+}
+
+unsigned int
+exgpio_get_bit(unsigned int gpio)
+{
+       struct exgpio_softc *sc = exgpio_pin_to_inst(gpio);
+
+       return sc->sc_get_bit(sc, gpio);
+}
+
+void
+exgpio_set_bit(unsigned int gpio)
+{
+       struct exgpio_softc *sc = exgpio_pin_to_inst(gpio);
+
+       sc->sc_set_bit(sc, gpio);
+}
+
+void
+exgpio_clear_bit(unsigned int gpio)
+{
+       struct exgpio_softc *sc = exgpio_pin_to_inst(gpio);
+
+       sc->sc_clear_bit(sc, gpio);
+}
+void
+exgpio_set_dir(unsigned int gpio, unsigned int dir)
+{
+       struct exgpio_softc *sc = exgpio_pin_to_inst(gpio);
+
+       sc->sc_set_dir(sc, gpio, dir);
+}
+
+unsigned int
+exgpio_v5_get_bit(struct exgpio_softc *sc, unsigned int gpio)
+{
+       u_int32_t val;
+
+       gpio = exgpio_pin_to_offset(gpio);
+       val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio));
+
+       return !!(val & GPIO_DAT_SET(gpio));
+}
+
+void
+exgpio_v5_set_bit(struct exgpio_softc *sc, unsigned int gpio)
+{
+       u_int32_t val;
+
+       gpio = exgpio_pin_to_offset(gpio);
+       val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio));
+
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio),
+               val | GPIO_DAT_SET(gpio));
+}
+
+void
+exgpio_v5_clear_bit(struct exgpio_softc *sc, unsigned int gpio)
+{
+       u_int32_t val;
+
+       gpio = exgpio_pin_to_offset(gpio);
+       val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio));
+
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio),
+               val & ~GPIO_DAT_MASK(gpio));
+}
+
+void
+exgpio_v5_set_dir(struct exgpio_softc *sc, unsigned int gpio, unsigned int dir)
+{
+       int s;
+       u_int32_t val;
+
+       gpio = exgpio_pin_to_offset(gpio);
+       s = splhigh();
+
+       val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_CON(gpio));
+       val &= ~GPIO_CON_OUTPUT(gpio);
+       if (dir == EXGPIO_DIR_OUT)
+               val |= GPIO_CON_OUTPUT(gpio);
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_CON(gpio), val);
+
+       splx(s);
+}
+
+unsigned int
+exgpio_v5_get_dir(struct exgpio_softc *sc, unsigned int gpio)
+{
+       int s;
+       u_int32_t val;
+
+       gpio = exgpio_pin_to_offset(gpio);
+       s = splhigh();
+
+       val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_CON(gpio));
+       if (val & GPIO_CON_OUTPUT(gpio))
+               val = EXGPIO_DIR_OUT;
+       else
+               val = EXGPIO_DIR_IN;
+
+       splx(s);
+       return val;
+}
diff --git a/sys/arch/armv7/exynos/exgpiovar.h b/sys/arch/armv7/exynos/exgpiovar.h
new file mode 100644 (file)
index 0000000..a53b9fe
--- /dev/null
@@ -0,0 +1,41 @@
+/* $OpenBSD: exgpiovar.h,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
+/*
+ * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef EXGPIOVAR_H
+#define EXGPIOVAR_H
+
+#define EXGPIO_DIR_IN  0
+#define EXGPIO_DIR_OUT 1
+
+unsigned int exgpio_get_function(unsigned int gpio, unsigned int fn);
+void exgpio_set_function(unsigned int gpio, unsigned int fn);
+unsigned int exgpio_get_bit(unsigned int gpio);
+void exgpio_set_bit(unsigned int gpio);
+void exgpio_clear_bit(unsigned int gpio);
+void exgpio_set_dir(unsigned int gpio, unsigned int dir);
+
+/* interrupts */
+void exgpio_clear_intr(unsigned int gpio);
+void exgpio_intr_mask(unsigned int gpio);
+void exgpio_intr_unmask(unsigned int gpio);
+void exgpio_intr_level(unsigned int gpio, unsigned int level);
+void *exgpio_intr_establish(unsigned int gpio, int level, int spl,
+    int (*func)(void *), void *arg, char *name);
+void exgpio_intr_disestablish(void *cookie);
+
+#endif /* EXGPIOVAR_H */
diff --git a/sys/arch/armv7/exynos/exiic.c b/sys/arch/armv7/exynos/exiic.c
new file mode 100644 (file)
index 0000000..e47f156
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <armv7/armv7/armv7var.h>
+#include <armv7/exynos/exgpiovar.h>
+#include <armv7/exynos/exiicvar.h>
+#include <armv7/exynos/exclockvar.h>
+
+/* registers */
+#define I2C_CON                                0x00    /* control register */
+#define I2C_STAT                       0x04    /* control/status register */
+#define I2C_ADD                                0x08    /* address register */
+#define I2C_DS                         0x0C    /* transmit/receive data shift register */
+#define I2C_LC                         0x10    /* multi-master line control register */
+
+/* bits and bytes */
+#define I2C_CON_TXCLKVAL_MASK          (0xf << 0) /* tx clock = i2cclk / (i2ccon[3:0] + 1) */
+#define I2C_CON_INTPENDING             (0x1 << 4) /* 0 = no interrupt pending/clear, 1 = pending */
+#define I2C_CON_TXRX_INT               (0x1 << 5) /* enable/disable */
+#define I2C_CON_TXCLKSRC_16            (0x0 << 6) /* i2clk = fpclk/16 */
+#define I2C_CON_TXCLKSRC_512           (0x1 << 6) /* i2clk = fpclk/512 */
+#define I2C_CON_ACK                    (0x1 << 7)
+#define I2C_STAT_LAST_RVCD_BIT         (0x1 << 0) /* last received bit 0 => ack, 1 => no ack */
+#define I2C_STAT_ADDR_ZERO_FLAG                (0x1 << 1) /* 0 => start/stop cond. detected, 1 => received slave addr 0xb */
+#define I2C_STAT_ADDR_SLAVE_ZERO_FLAG  (0x1 << 2) /* 0 => start/stop cond. detected, 1 => received slave addr matches i2cadd */
+#define I2C_STAT_ARBITRATION           (0x1 << 3) /* 0 => successul, 1 => failed */
+#define I2C_STAT_SERIAL_OUTPUT         (0x1 << 4) /* 0 => disable tx/rx, 1 => enable tx/rx */
+#define I2C_STAT_BUSY_SIGNAL           (0x1 << 5) /* 0 => not busy / stop signal generation, 1 => busy / start signal generation */
+#define I2C_STAT_MODE_SEL_SLAVE_RX     (0x0 << 6) /* slave receive mode */
+#define I2C_STAT_MODE_SEL_SLAVE_TX     (0x1 << 6) /* slave transmit mode */
+#define I2C_STAT_MODE_SEL_MASTER_RX    (0x2 << 6) /* master receive mode */
+#define I2C_STAT_MODE_SEL_MASTER_TX    (0x3 << 6) /* master transmit */
+#define I2C_ADD_SLAVE_ADDR(x)          (((x) & 0x7f) << 1)
+#define I2C_DS_DATA_SHIFT(x)           (((x) & 0xff) << 0)
+
+#define I2C_ACK                                0
+#define I2C_NACK                       1
+#define I2C_TIMEOUT                    2
+
+struct exiic_softc {
+       struct device           sc_dev;
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh;
+       bus_size_t              sc_ios;
+       void                    *sc_ih;
+       int                     unit;
+
+       struct rwlock           sc_buslock;
+       struct i2c_controller   i2c_tag;
+
+       uint16_t                frequency;
+       uint16_t                intr_status;
+};
+
+int exiic_match(struct device *parent, void *v, void *aux);
+void exiic_attach(struct device *, struct device *, void *);
+int exiic_detach(struct device *, int);
+void exiic_bus_scan(struct device *, struct i2cbus_attach_args *, void *);
+void exiic_setspeed(struct exiic_softc *, int);
+int exiic_intr(void *);
+int exiic_wait_intr(struct exiic_softc *, int, int);
+int exiic_wait_state(struct exiic_softc *, uint32_t, uint32_t, uint32_t);
+int exiic_start(struct exiic_softc *, int, int, void *, int);
+
+void exiic_xfer_start(struct exiic_softc *);
+int exiic_xfer_wait(struct exiic_softc *);
+int exiic_i2c_acquire_bus(void *, int);
+void exiic_i2c_release_bus(void *, int);
+int exiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
+    void *, size_t, int);
+
+#define HREAD4(sc, reg)                                                        \
+       (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
+#define HWRITE4(sc, reg, val)                                          \
+       bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+#define HSET4(sc, reg, bits)                                           \
+       HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
+#define HCLR4(sc, reg, bits)                                           \
+       HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
+
+
+struct cfattach exiic_ca = {
+       sizeof(struct exiic_softc), NULL, exiic_attach, exiic_detach
+};
+struct cfattach exiic_fdt_ca = {
+       sizeof(struct exiic_softc), exiic_match, exiic_attach, exiic_detach
+};
+
+struct cfdriver exiic_cd = {
+       NULL, "exiic", DV_DULL
+};
+
+int
+exiic_match(struct device *parent, void *v, void *aux)
+{
+       struct armv7_attach_args *aa = aux;
+
+       if (fdt_node_compatible("samsung,s3c2440-i2c", aa->aa_node))
+               return 1;
+
+       return 0;
+}
+
+void
+exiic_attach(struct device *parent, struct device *self, void *args)
+{
+       struct exiic_softc *sc = (struct exiic_softc *)self;
+       struct armv7_attach_args *aa = args;
+       struct fdt_memory mem;
+
+       sc->sc_iot = aa->aa_iot;
+       if (aa->aa_node) {
+               static int unit = 0;
+
+               sc->unit = unit++;
+               if (fdt_get_memory_address(aa->aa_node, 0, &mem))
+                       panic("%s: could not extract memory data from FDT",
+                           __func__);
+       } else {
+               mem.addr = aa->aa_dev->mem[0].addr;
+               mem.size = aa->aa_dev->mem[0].size;
+               sc->unit = aa->aa_dev->unit;
+       }
+       if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh))
+               panic("%s: bus_space_map failed!", __func__);
+       sc->sc_ios = mem.size;
+
+#if 0
+       sc->sc_ih = arm_intr_establish(aa->aa_dev->irq[0], IPL_BIO,
+           exiic_intr, sc, sc->sc_dev.dv_xname);
+#endif
+
+       printf("\n");
+
+       rw_init(&sc->sc_buslock, sc->sc_dev.dv_xname);
+
+       struct i2cbus_attach_args iba;
+
+       sc->i2c_tag.ic_cookie = sc;
+       sc->i2c_tag.ic_acquire_bus = exiic_i2c_acquire_bus;
+       sc->i2c_tag.ic_release_bus = exiic_i2c_release_bus;
+       sc->i2c_tag.ic_exec = exiic_i2c_exec;
+
+       bzero(&iba, sizeof iba);
+       iba.iba_name = "iic";
+       iba.iba_tag = &sc->i2c_tag;
+       iba.iba_bus_scan = exiic_bus_scan;
+       iba.iba_bus_scan_arg = sc;
+       config_found(&sc->sc_dev, &iba, NULL);
+}
+
+void
+exiic_bus_scan(struct device *self, struct i2cbus_attach_args *iba, void *arg)
+{
+       struct exiic_softc *sc = (struct exiic_softc *)arg;
+       struct i2c_attach_args ia;
+
+       /* XXX: We currently only attach cros-ec on I2C4.  We'll use FDT later. */
+       if (sc->unit != 4)
+               return;
+
+       char *name = "crosec";
+       int addr = 0x1e;
+
+       memset(&ia, 0, sizeof(ia));
+       ia.ia_tag = iba->iba_tag;
+       ia.ia_addr = addr;
+       ia.ia_size = 1;
+       ia.ia_name = name;
+       config_found(self, &ia, iicbus_print);
+
+       name = "tps65090";
+       addr = 0x48;
+
+       memset(&ia, 0, sizeof(ia));
+       ia.ia_tag = iba->iba_tag;
+       ia.ia_addr = addr;
+       ia.ia_size = 1;
+       ia.ia_name = name;
+       config_found(self, &ia, iicbus_print);
+}
+
+void
+exiic_setspeed(struct exiic_softc *sc, int speed)
+{
+       if (!sc->frequency) {
+               uint32_t freq, div = 0, pres = 16;
+               freq = exclock_get_i2cclk();
+
+               /* calculate prescaler and divisor values */
+               if ((freq / pres / (16 + 1)) > speed)
+                       /* set prescaler to 512 */
+                       pres = 512;
+
+               while ((freq / pres / (div + 1)) > speed)
+                       div++;
+
+               /* set prescaler, divisor according to freq, also set ACKGEN, IRQ */
+               sc->frequency = (div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0);
+       }
+
+       HWRITE4(sc, I2C_CON, sc->frequency);
+}
+
+#if 0
+int
+exiic_intr(void *arg)
+{
+       struct exiic_softc *sc = arg;
+       u_int16_t status;
+       int rc = 0;
+
+       status = HREAD4(sc, I2C_CON);
+
+       if (ISSET(status, I2C_CON_INTPENDING)) {
+               /* we do not acknowledge the interrupt here */
+               rc = 1;
+
+               sc->intr_status |= status;
+               wakeup(&sc->intr_status);
+       }
+
+       return (rc);
+}
+
+int
+exiic_wait_intr(struct exiic_softc *sc, int mask, int timo)
+{
+       int status;
+       int s;
+
+       s = splbio();
+
+       status = sc->intr_status & mask;
+       while (status == 0) {
+               if (tsleep(&sc->intr_status, PWAIT, "hcintr", timo)
+                   == EWOULDBLOCK) {
+                       break;
+               }
+               status = sc->intr_status & mask;
+       }
+       status = sc->intr_status & mask;
+       sc->intr_status &= ~status;
+
+       splx(s);
+       return status;
+}
+#endif
+
+int
+exiic_wait_state(struct exiic_softc *sc, uint32_t reg, uint32_t mask, uint32_t value)
+{
+       uint32_t state;
+       int timeout;
+       state = HREAD4(sc, reg);
+       for (timeout = 1000; timeout > 0; timeout--) {
+               if (((state = HREAD4(sc, reg)) & mask) == value)
+                       return 0;
+               delay(1000);
+       }
+       return ETIMEDOUT;
+}
+
+int
+exiic_i2c_acquire_bus(void *cookie, int flags)
+{
+       struct exiic_softc *sc = cookie;
+       int ret = rw_enter(&sc->sc_buslock, RW_WRITE);
+
+       if (!ret) {
+               /* set speed to 100 Kbps */
+               exiic_setspeed(sc, 100);
+
+               /* STOP */
+               HWRITE4(sc, I2C_STAT, 0);
+               HWRITE4(sc, I2C_ADD, 0);
+               HWRITE4(sc, I2C_STAT, I2C_STAT_MODE_SEL_MASTER_TX
+                                   | I2C_STAT_SERIAL_OUTPUT);
+       }
+
+       return ret;
+}
+
+void
+exiic_i2c_release_bus(void *cookie, int flags)
+{
+       struct exiic_softc *sc = cookie;
+
+       (void) rw_exit(&sc->sc_buslock);
+}
+
+int
+exiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t _addr,
+    const void *cmdbuf, size_t cmdlen, void *databuf, size_t datalen, int flags)
+{
+       struct exiic_softc *sc = cookie;
+       uint32_t ret = 0;
+       u_int8_t addr = 0;
+       int i = 0;
+
+       addr = (_addr & 0x7f) << 1;
+
+       /* clock gating */
+       //exccm_enable_i2c(sc->unit);
+
+       if (exiic_wait_state(sc, I2C_STAT, I2C_STAT_BUSY_SIGNAL, 0)) {
+               printf("%s: busy\n", __func__);
+               return (EIO);
+       }
+
+       /* acknowledge generation */
+       HSET4(sc, I2C_CON, I2C_CON_ACK);
+
+       /* Send the slave-address */
+       HWRITE4(sc, I2C_DS, addr);
+       if (!I2C_OP_READ_P(op) || (cmdbuf && cmdlen))
+               HWRITE4(sc, I2C_STAT, I2C_STAT_MODE_SEL_MASTER_TX
+                                   | I2C_STAT_SERIAL_OUTPUT
+                                   | I2C_STAT_BUSY_SIGNAL);
+       else
+               HWRITE4(sc, I2C_STAT, I2C_STAT_MODE_SEL_MASTER_RX
+                                   | I2C_STAT_SERIAL_OUTPUT
+                                   | I2C_STAT_BUSY_SIGNAL);
+
+       ret = exiic_xfer_wait(sc);
+       if (ret != I2C_ACK)
+               goto fail;
+
+       /* transmit commands */
+       if (cmdbuf && cmdlen) {
+               for (i = 0; i < cmdlen; i++) {
+                       HWRITE4(sc, I2C_DS, ((uint8_t *)cmdbuf)[i]);
+                       exiic_xfer_start(sc);
+                       ret = exiic_xfer_wait(sc);
+                       if (ret != I2C_ACK)
+                               goto fail;
+               }
+       }
+
+       if (I2C_OP_READ_P(op)) {
+               if (cmdbuf && cmdlen) {
+                       /* write slave chip address again for actual read */
+                       HWRITE4(sc, I2C_DS, addr);
+
+                       /* restart */
+                       HWRITE4(sc, I2C_STAT, I2C_STAT_MODE_SEL_MASTER_RX
+                                           | I2C_STAT_SERIAL_OUTPUT
+                                           | I2C_STAT_BUSY_SIGNAL);
+                       exiic_xfer_start(sc);
+                       ret = exiic_xfer_wait(sc);
+                       if (ret != I2C_ACK)
+                               goto fail;
+               }
+
+               for (i = 0; i < datalen && ret == I2C_ACK; i++) {
+                       /* disable ACK for final read */
+                       if (i == datalen - 1)
+                               HCLR4(sc, I2C_CON, I2C_CON_ACK);
+                       exiic_xfer_start(sc);
+                       ret = exiic_xfer_wait(sc);
+                       ((uint8_t *)databuf)[i] = HREAD4(sc, I2C_DS);
+               }
+               if (ret == I2C_NACK)
+                       ret = I2C_ACK; /* Normal terminated read. */
+       } else {
+               for (i = 0; i < datalen && ret == I2C_ACK; i++) {
+                       HWRITE4(sc, I2C_DS, ((uint8_t *)databuf)[i]);
+                       exiic_xfer_start(sc);
+                       ret = exiic_xfer_wait(sc);
+               }
+       }
+
+fail:
+       /* send STOP */
+       if (op & I2C_OP_READ_WITH_STOP) {
+               HWRITE4(sc, I2C_STAT, I2C_STAT_MODE_SEL_MASTER_RX
+                                   | I2C_STAT_SERIAL_OUTPUT);
+               exiic_xfer_start(sc);
+       }
+
+       return ret;
+}
+
+void
+exiic_xfer_start(struct exiic_softc *sc)
+{
+       HCLR4(sc, I2C_CON, I2C_CON_INTPENDING);
+}
+
+int
+exiic_xfer_wait(struct exiic_softc *sc)
+{
+       if (!exiic_wait_state(sc, I2C_CON, I2C_CON_INTPENDING,
+                                          I2C_CON_INTPENDING))
+               return (HREAD4(sc, I2C_STAT) & I2C_STAT_LAST_RVCD_BIT) ?
+                       I2C_NACK : I2C_ACK;
+       else
+               return I2C_TIMEOUT;
+}
+
+int
+exiic_detach(struct device *self, int flags)
+{
+       struct exiic_softc *sc = (struct exiic_softc *)self;
+
+       bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
+       return 0;
+}
diff --git a/sys/arch/armv7/exynos/exiicvar.h b/sys/arch/armv7/exynos/exiicvar.h
new file mode 100644 (file)
index 0000000..8a70257
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef EXIICVAR_H
+#define EXIICVAR_H
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/systm.h>
+#include <sys/rwlock.h>
+
+#include <dev/i2c/i2cvar.h>
+
+#endif
diff --git a/sys/arch/armv7/exynos/exmct.c b/sys/arch/armv7/exynos/exmct.c
new file mode 100644 (file)
index 0000000..37c7180
--- /dev/null
@@ -0,0 +1,117 @@
+/* $OpenBSD: exmct.c,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
+/*
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/evcount.h>
+#include <sys/socket.h>
+#include <sys/timeout.h>
+#include <arm/cpufunc.h>
+#include <machine/intr.h>
+#include <machine/bus.h>
+#include <machine/fdt.h>
+#include <armv7/armv7/armv7var.h>
+
+/* registers */
+#define MCT_CTRL       0x240
+#define MCT_WRITE_STAT 0x24C
+
+/* bits and bytes */
+#define MCT_CTRL_START (1 << 8)
+
+struct exmct_softc {
+       struct device           sc_dev;
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh;
+};
+
+struct exmct_softc *exmct_sc;
+
+int exmct_match(struct device *parent, void *v, void *aux);
+void exmct_attach(struct device *parent, struct device *self, void *args);
+void exmct_stop(void);
+void exmct_reset(void);
+
+struct cfattach        exmct_ca = {
+       sizeof (struct exmct_softc), NULL, exmct_attach
+};
+struct cfattach        exmct_fdt_ca = {
+       sizeof (struct exmct_softc), exmct_match, exmct_attach
+};
+
+struct cfdriver exmct_cd = {
+       NULL, "exmct", DV_DULL
+};
+
+int
+exmct_match(struct device *parent, void *v, void *aux)
+{
+       struct armv7_attach_args *aa = aux;
+
+       if (fdt_node_compatible("samsung,exynos4210-mct", aa->aa_node))
+               return 1;
+
+       return 0;
+}
+
+void
+exmct_attach(struct device *parent, struct device *self, void *args)
+{
+       struct armv7_attach_args *aa = args;
+       struct exmct_softc *sc = (struct exmct_softc *) self;
+       struct fdt_memory mem;
+       uint32_t i, mask, reg;
+
+       sc->sc_iot = aa->aa_iot;
+       if (aa->aa_node) {
+               if (fdt_get_memory_address(aa->aa_node, 0, &mem))
+                       panic("%s: could not extract memory data from FDT",
+                           __func__);
+       } else {
+               mem.addr = aa->aa_dev->mem[0].addr;
+               mem.size = aa->aa_dev->mem[0].size;
+       }
+       if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh))
+               panic("%s: bus_space_map failed!", __func__);
+
+       printf("\n");
+
+       exmct_sc = sc;
+
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, MCT_CTRL,
+           bus_space_read_4(sc->sc_iot, sc->sc_ioh, MCT_CTRL) | MCT_CTRL_START);
+
+       mask = (1 << 16);
+
+       /* Wait 10 times until written value is applied */
+       for (i = 0; i < 10; i++) {
+               reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MCT_WRITE_STAT);
+               if (reg & mask) {
+                       bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+                           MCT_WRITE_STAT, mask);
+                       return;
+               }
+               cpufunc_nullop();
+       }
+
+       /* NOTREACHED */
+
+       panic("%s: Can't enable timer!", __func__);
+}
diff --git a/sys/arch/armv7/exynos/expower.c b/sys/arch/armv7/exynos/expower.c
new file mode 100644 (file)
index 0000000..4bb4a2b
--- /dev/null
@@ -0,0 +1,114 @@
+/* $OpenBSD: expower.c,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
+/*
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/sysctl.h>
+#include <sys/device.h>
+#include <sys/evcount.h>
+#include <sys/socket.h>
+#include <sys/timeout.h>
+#include <machine/intr.h>
+#include <machine/bus.h>
+#include <machine/fdt.h>
+#include <armv7/armv7/armv7var.h>
+#include <armv7/exynos/expowervar.h>
+
+/* registers */
+#define POWER_PHY_CTRL                         0x708
+
+/* bits and bytes */
+#define POWER_PHY_CTRL_USB_HOST_EN             (1 << 0)
+
+#define HREAD4(sc, reg)                                                        \
+       (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
+#define HWRITE4(sc, reg, val)                                          \
+       bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+#define HSET4(sc, reg, bits)                                           \
+       HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
+#define HCLR4(sc, reg, bits)                                           \
+       HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
+
+struct expower_softc {
+       struct device           sc_dev;
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh;
+};
+
+struct expower_softc *expower_sc;
+
+int expower_match(struct device *parent, void *v, void *aux);
+void expower_attach(struct device *parent, struct device *self, void *args);
+
+struct cfattach        expower_ca = {
+       sizeof (struct expower_softc), NULL, expower_attach
+};
+struct cfattach        expower_fdt_ca = {
+       sizeof (struct expower_softc), expower_match, expower_attach
+};
+
+struct cfdriver expower_cd = {
+       NULL, "expower", DV_DULL
+};
+
+int
+expower_match(struct device *parent, void *v, void *aux)
+{
+       struct armv7_attach_args *aa = aux;
+
+       if (fdt_node_compatible("samsung,exynos5250-pmu", aa->aa_node))
+               return 1;
+
+       return 0;
+}
+
+void
+expower_attach(struct device *parent, struct device *self, void *args)
+{
+       struct armv7_attach_args *aa = args;
+       struct expower_softc *sc = (struct expower_softc *) self;
+       struct fdt_memory mem;
+
+       sc->sc_iot = aa->aa_iot;
+       if (aa->aa_node) {
+               if (fdt_get_memory_address(aa->aa_node, 0, &mem))
+                       panic("%s: could not extract memory data from FDT",
+                           __func__);
+       } else {
+               mem.addr = aa->aa_dev->mem[0].addr;
+               mem.size = aa->aa_dev->mem[0].size;
+       }
+       if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh))
+               panic("%s: bus_space_map failed!", __func__);
+
+       printf("\n");
+
+       expower_sc = sc;
+}
+
+void
+expower_usbhost_phy_ctrl(int on)
+{
+       struct expower_softc *sc = expower_sc;
+
+       if (on)
+               HSET4(sc, POWER_PHY_CTRL, POWER_PHY_CTRL_USB_HOST_EN);
+       else
+               HCLR4(sc, POWER_PHY_CTRL, POWER_PHY_CTRL_USB_HOST_EN);
+}
diff --git a/sys/arch/armv7/exynos/expowervar.h b/sys/arch/armv7/exynos/expowervar.h
new file mode 100644 (file)
index 0000000..14e41bc
--- /dev/null
@@ -0,0 +1,23 @@
+/* $OpenBSD: expowervar.h,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
+/*
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef EXPOWERVAR_H
+#define EXPOWERVAR_H
+
+void expower_usbhost_phy_ctrl(int);
+
+#endif /* EXPOWERVAR_H */
diff --git a/sys/arch/armv7/exynos/exsysreg.c b/sys/arch/armv7/exynos/exsysreg.c
new file mode 100644 (file)
index 0000000..169ecc0
--- /dev/null
@@ -0,0 +1,114 @@
+/* $OpenBSD: exsysreg.c,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
+/*
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/sysctl.h>
+#include <sys/device.h>
+#include <sys/evcount.h>
+#include <sys/socket.h>
+#include <sys/timeout.h>
+#include <machine/intr.h>
+#include <machine/bus.h>
+#include <machine/fdt.h>
+#include <armv7/armv7/armv7var.h>
+#include <armv7/exynos/exsysregvar.h>
+
+/* registers */
+#define SYSREG_USB20PHY_CFG                    0x230
+
+/* bits and bytes */
+#define SYSREG_USB20PHY_CFG_HOST_LINK_EN       (1 << 0)
+
+#define HREAD4(sc, reg)                                                        \
+       (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
+#define HWRITE4(sc, reg, val)                                          \
+       bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+#define HSET4(sc, reg, bits)                                           \
+       HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
+#define HCLR4(sc, reg, bits)                                           \
+       HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
+
+struct exsysreg_softc {
+       struct device           sc_dev;
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh;
+};
+
+struct exsysreg_softc *exsysreg_sc;
+
+int exsysreg_match(struct device *parent, void *v, void *aux);
+void exsysreg_attach(struct device *parent, struct device *self, void *args);
+
+struct cfattach        exsysreg_ca = {
+       sizeof (struct exsysreg_softc), NULL, exsysreg_attach
+};
+struct cfattach        exsysreg_fdt_ca = {
+       sizeof (struct exsysreg_softc), exsysreg_match, exsysreg_attach
+};
+
+struct cfdriver exsysreg_cd = {
+       NULL, "exsysreg", DV_DULL
+};
+
+int
+exsysreg_match(struct device *parent, void *v, void *aux)
+{
+       struct armv7_attach_args *aa = aux;
+
+       if (fdt_node_compatible("samsung,exynos5-sysreg", aa->aa_node))
+               return 1;
+
+       return 0;
+}
+
+void
+exsysreg_attach(struct device *parent, struct device *self, void *args)
+{
+       struct armv7_attach_args *aa = args;
+       struct exsysreg_softc *sc = (struct exsysreg_softc *) self;
+       struct fdt_memory mem;
+
+       sc->sc_iot = aa->aa_iot;
+       if (aa->aa_node) {
+               if (fdt_get_memory_address(aa->aa_node, 0, &mem))
+                       panic("%s: could not extract memory data from FDT",
+                           __func__);
+       } else {
+               mem.addr = aa->aa_dev->mem[0].addr;
+               mem.size = aa->aa_dev->mem[0].size;
+       }
+       if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh))
+               panic("%s: bus_space_map failed!", __func__);
+
+       printf("\n");
+
+       exsysreg_sc = sc;
+}
+
+void
+exsysreg_usbhost_mode(int on)
+{
+       struct exsysreg_softc *sc = exsysreg_sc;
+
+       if (on)
+               HSET4(sc, SYSREG_USB20PHY_CFG, SYSREG_USB20PHY_CFG_HOST_LINK_EN);
+       else
+               HCLR4(sc, SYSREG_USB20PHY_CFG, SYSREG_USB20PHY_CFG_HOST_LINK_EN);
+}
diff --git a/sys/arch/armv7/exynos/exsysregvar.h b/sys/arch/armv7/exynos/exsysregvar.h
new file mode 100644 (file)
index 0000000..de4bbb0
--- /dev/null
@@ -0,0 +1,23 @@
+/* $OpenBSD: exsysregvar.h,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
+/*
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef EXSYSREGVAR_H
+#define EXSYSREGVAR_H
+
+void exsysreg_usbhost_mode(int);
+
+#endif /* EXSYSREGVAR_H */
diff --git a/sys/arch/armv7/exynos/exuart.c b/sys/arch/armv7/exynos/exuart.c
new file mode 100644 (file)
index 0000000..9e2c114
--- /dev/null
@@ -0,0 +1,888 @@
+/* $OpenBSD: exuart.c,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
+/*
+ * Copyright (c) 2005 Dale Rahn <drahn@motorola.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/device.h>
+#include <sys/syslog.h>
+#include <sys/conf.h>
+#include <sys/fcntl.h>
+#include <sys/select.h>
+#include <sys/kernel.h>
+
+#include <dev/cons.h>
+
+
+#ifdef DDB
+#include <ddb/db_var.h>
+#endif
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+#include <armv7/exynos/exuartreg.h>
+#include <armv7/exynos/exuartvar.h>
+#include <armv7/armv7/armv7var.h>
+#include <armv7/exynos/exclockvar.h>
+
+#define DEVUNIT(x)      (minor(x) & 0x7f)
+#define DEVCUA(x)       (minor(x) & 0x80)
+
+struct exuart_softc {
+       struct device   sc_dev;
+       bus_space_tag_t sc_iot;
+       bus_space_handle_t sc_ioh;
+       struct soft_intrhand *sc_si;
+       void *sc_irq;
+       struct tty      *sc_tty;
+       struct timeout  sc_diag_tmo;
+       struct timeout  sc_dtr_tmo;
+       int             sc_fifo;
+       int             sc_overflows;
+       int             sc_floods;
+       int             sc_errors;
+       int             sc_halt;
+       u_int32_t       sc_ulcon;
+       u_int32_t       sc_ucon;
+       u_int32_t       sc_ufcon;
+       u_int32_t       sc_umcon;
+       u_int8_t        sc_hwflags;
+#define COM_HW_NOIEN    0x01
+#define COM_HW_FIFO     0x02
+#define COM_HW_SIR      0x20
+#define COM_HW_CONSOLE  0x40
+#define COM_HW_KGDB     0x80
+       u_int8_t        sc_swflags;
+#define COM_SW_SOFTCAR  0x01
+#define COM_SW_CLOCAL   0x02
+#define COM_SW_CRTSCTS  0x04
+#define COM_SW_MDMBUF   0x08
+#define COM_SW_PPS      0x10
+
+       u_int8_t        sc_initialize;
+       u_int8_t        sc_cua;
+       u_int16_t       *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
+#define EXUART_IBUFSIZE 128
+#define EXUART_IHIGHWATER 100
+       u_int16_t               sc_ibufs[2][EXUART_IBUFSIZE];
+};
+
+
+int     exuartprobe(struct device *parent, void *self, void *aux);
+int     exuartprobe_fdt(struct device *parent, void *self, void *aux);
+void    exuartattach(struct device *parent, struct device *self, void *aux);
+
+void exuartcnprobe(struct consdev *cp);
+void exuartcnprobe(struct consdev *cp);
+void exuartcninit(struct consdev *cp);
+int exuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
+    tcflag_t cflag);
+int exuartcngetc(dev_t dev);
+void exuartcnputc(dev_t dev, int c);
+void exuartcnpollc(dev_t dev, int on);
+int  exuart_param(struct tty *tp, struct termios *t);
+void exuart_start(struct tty *);
+void exuart_pwroff(struct exuart_softc *sc);
+void exuart_diag(void *arg);
+void exuart_raisedtr(void *arg);
+void exuart_softint(void *arg);
+struct exuart_softc *exuart_sc(dev_t dev);
+
+int exuart_intr(void *);
+
+
+/* XXX - we imitate 'com' serial ports and take over their entry points */
+/* XXX: These belong elsewhere */
+cdev_decl(exuart);
+
+struct cfdriver exuart_cd = {
+       NULL, "exuart", DV_TTY
+};
+
+struct cfattach exuart_ca = {
+       sizeof(struct exuart_softc), exuartprobe, exuartattach
+};
+struct cfattach exuart_fdt_ca = {
+       sizeof(struct exuart_softc), exuartprobe_fdt, exuartattach
+};
+
+bus_space_tag_t        exuartconsiot;
+bus_space_handle_t exuartconsioh;
+bus_addr_t     exuartconsaddr;
+tcflag_t       exuartconscflag = TTYDEF_CFLAG;
+int            exuartdefaultrate = B115200;
+
+int
+exuartprobe(struct device *parent, void *self, void *aux)
+{
+       return 1;
+}
+
+int
+exuartprobe_fdt(struct device *parent, void *self, void *aux)
+{
+       struct armv7_attach_args *aa = aux;
+
+       if (fdt_node_compatible("samsung,exynos4210-uart", aa->aa_node))
+               return 1;
+
+       return 0;
+}
+
+struct cdevsw exuartdev =
+       cdev_tty_init(3/*XXX NEXUART */ ,exuart);               /* 12: serial port */
+
+void
+exuartattach(struct device *parent, struct device *self, void *args)
+{
+       struct armv7_attach_args *aa = args;
+       struct exuart_softc *sc = (struct exuart_softc *) self;
+       struct fdt_memory mem;
+       int irq;
+
+       sc->sc_iot = aa->aa_iot;
+       if (aa->aa_node) {
+               uint32_t ints[3];
+
+               if (fdt_get_memory_address(aa->aa_node, 0, &mem))
+                       panic("%s: could not extract memory data from FDT",
+                           __func__);
+
+               /* TODO: Add interrupt FDT API. */
+               if (fdt_node_property_ints(aa->aa_node, "interrupts",
+                   ints, 3) != 3)
+                       panic("%s: could not extract interrupt data from FDT",
+                           __func__);
+
+               irq = ints[1];
+       } else {
+               irq = aa->aa_dev->irq[0];
+               mem.addr = aa->aa_dev->mem[0].addr;
+               mem.size = aa->aa_dev->mem[0].size;
+       }
+
+       sc->sc_irq = arm_intr_establish(irq, IPL_TTY,
+           exuart_intr, sc, sc->sc_dev.dv_xname);
+       if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh))
+               panic("%s: bus_space_map failed!", __func__);
+
+       if (mem.addr == exuartconsaddr)
+               printf(" console");
+
+       timeout_set(&sc->sc_diag_tmo, exuart_diag, sc);
+       timeout_set(&sc->sc_dtr_tmo, exuart_raisedtr, sc);
+       sc->sc_si = softintr_establish(IPL_TTY, exuart_softint, sc);
+
+       if(sc->sc_si == NULL)
+               panic("%s: can't establish soft interrupt.",
+                   sc->sc_dev.dv_xname);
+
+       printf("\n");
+}
+
+int
+exuart_intr(void *arg)
+{
+#if 0
+       struct exuart_softc *sc = arg;
+       bus_space_tag_t iot = sc->sc_iot;
+       bus_space_handle_t ioh = sc->sc_ioh;
+       struct tty *tp = sc->sc_tty;
+       u_int32_t reg;
+       u_int16_t *p;
+       u_int16_t c;
+
+       sr1 = bus_space_read_2(iot, ioh, EXUART_USR1);
+       if (ISSET(sr1, EXUART_SR1_TRDY) && ISSET(tp->t_state, TS_BUSY)) {
+               CLR(tp->t_state, TS_BUSY | TS_FLUSH);
+               if (sc->sc_halt > 0)
+                       wakeup(&tp->t_outq);
+               (*linesw[tp->t_line].l_start)(tp);
+       }
+
+       if (sc->sc_tty == NULL)
+               return(0);
+
+       if(!ISSET(bus_space_read_2(iot, ioh, EXUART_USR2), EXUART_SR2_RDR))
+               return 0;
+
+       p = sc->sc_ibufp;
+
+       while(ISSET(bus_space_read_2(iot, ioh, EXUART_USR2), EXUART_SR2_RDR)) {
+               c = bus_space_read_1(iot, ioh, EXUART_URXH);
+               if (p >= sc->sc_ibufend) {
+                       sc->sc_floods++;
+                       if (sc->sc_errors++ == 0)
+                               timeout_add(&sc->sc_diag_tmo, 60 * hz);
+               } else {
+                       *p++ = c;
+                       if (p == sc->sc_ibufhigh && ISSET(tp->t_cflag, CRTSCTS))
+                               /* XXX */
+                               //CLR(sc->sc_ucr3, EXUART_CR3_DSR);
+                               //bus_space_write_2(iot, ioh, EXUART_UCR3,
+                               //    sc->sc_ucr3);
+
+               }
+               /* XXX - msr stuff ? */
+       }
+       sc->sc_ibufp = p;
+
+       softintr_schedule(sc->sc_si);
+#endif
+
+       return 1;
+}
+
+int
+exuart_param(struct tty *tp, struct termios *t)
+{
+       struct exuart_softc *sc = exuart_cd.cd_devs[DEVUNIT(tp->t_dev)];
+       bus_space_tag_t iot = sc->sc_iot;
+       bus_space_handle_t ioh = sc->sc_ioh;
+       int ospeed = t->c_ospeed;
+       int error;
+       tcflag_t oldcflag;
+
+
+       if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
+               return EINVAL;
+
+       switch (ISSET(t->c_cflag, CSIZE)) {
+       case CS5:
+               CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK);
+               SET(sc->sc_ulcon, EXUART_ULCON_WORD_FIVE);
+               break;
+       case CS6:
+               CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK);
+               SET(sc->sc_ulcon, EXUART_ULCON_WORD_SIX);
+               break;
+       case CS7:
+               CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK);
+               SET(sc->sc_ulcon, EXUART_ULCON_WORD_SEVEN);
+               break;
+       case CS8:
+               CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK);
+               SET(sc->sc_ulcon, EXUART_ULCON_WORD_EIGHT);
+               break;
+       }
+
+       CLR(sc->sc_ulcon, EXUART_ULCON_PARITY_MASK);
+       if (ISSET(t->c_cflag, PARENB)) {
+               if (ISSET(t->c_cflag, PARODD))
+                       SET(sc->sc_ulcon, EXUART_ULCON_PARITY_ODD);
+               else
+                       SET(sc->sc_ulcon, EXUART_ULCON_PARITY_EVEN);
+       }
+
+       if (ISSET(t->c_cflag, CSTOPB))
+               SET(sc->sc_ulcon, EXUART_ULCON_STOP_TWO);
+       else
+               CLR(sc->sc_ulcon, EXUART_ULCON_STOP_ONE);
+
+       bus_space_write_4(iot, ioh, EXUART_ULCON, sc->sc_ulcon);
+
+       if (ospeed == 0) {
+               /* lower dtr */
+       }
+
+       if (ospeed != 0) {
+               while (ISSET(tp->t_state, TS_BUSY)) {
+                       ++sc->sc_halt;
+                       error = ttysleep(tp, &tp->t_outq,
+                           TTOPRI | PCATCH, "exuartprm", 0);
+                       --sc->sc_halt;
+                       if (error) {
+                               exuart_start(tp);
+                               return (error);
+                       }
+               }
+               /* set speed */
+       }
+
+       /* setup fifo */
+
+       /* When not using CRTSCTS, RTS follows DTR. */
+       /* sc->sc_dtr = MCR_DTR; */
+
+
+       /* and copy to tty */
+       tp->t_ispeed = t->c_ispeed;
+       tp->t_ospeed = t->c_ospeed;
+       oldcflag = tp->t_cflag;
+       tp->t_cflag = t->c_cflag;
+
+        /*
+        * If DCD is off and MDMBUF is changed, ask the tty layer if we should
+        * stop the device.
+        */
+        /* XXX */
+
+       exuart_start(tp);
+
+       return 0;
+}
+
+void
+exuart_start(struct tty *tp)
+{
+        struct exuart_softc *sc = exuart_cd.cd_devs[DEVUNIT(tp->t_dev)];
+       bus_space_tag_t iot = sc->sc_iot;
+       bus_space_handle_t ioh = sc->sc_ioh;
+
+       int s;
+       s = spltty();
+       if (ISSET(tp->t_state, TS_BUSY)) {
+               splx(s);
+               return;
+       }
+       if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP))
+               goto stopped;
+#ifdef DAMNFUCKSHIT
+       /* clear to send (IE the RTS pin on this shit) is not directly \
+        * readable - skip check for now
+        */
+       if (ISSET(tp->t_cflag, CRTSCTS) && !ISSET(sc->sc_msr, EXUART_CTS))
+               goto stopped;
+#endif
+       if (tp->t_outq.c_cc <= tp->t_lowat) {
+               if (ISSET(tp->t_state, TS_ASLEEP)) {
+                       CLR(tp->t_state, TS_ASLEEP);
+                       wakeup(&tp->t_outq);
+               }
+               if (tp->t_outq.c_cc == 0)
+                       goto stopped;
+               selwakeup(&tp->t_wsel);
+       }
+       SET(tp->t_state, TS_BUSY);
+
+#if 0
+       if (!ISSET(sc->sc_ucr1, EXUART_CR1_TXMPTYEN)) {
+               SET(sc->sc_ucr1, EXUART_CR1_TXMPTYEN);
+               bus_space_write_2(iot, ioh, EXUART_UCR1, sc->sc_ucr1);
+       }
+#endif
+
+       {
+               u_char buf[32];
+               int n = q_to_b(&tp->t_outq, buf, 32/*XXX*/);
+               int i;
+               for (i = 0; i < n; i++)
+                       bus_space_write_1(iot, ioh, EXUART_UTXH, buf[i]);
+       }
+       splx(s);
+       return;
+stopped:
+#if 0
+       if (ISSET(sc->sc_ucr1, )) {
+               CLR(sc->sc_ucr1, EXUART_CR1_TXMPTYEN);
+               bus_space_write_2(iot, ioh, EXUART_UCR1, sc->sc_ucr1);
+       }
+#endif
+       splx(s);
+}
+
+void
+exuart_pwroff(struct exuart_softc *sc)
+{
+}
+
+void
+exuart_diag(void *arg)
+{
+       struct exuart_softc *sc = arg;
+       int overflows, floods;
+       int s;
+
+       s = spltty();
+       sc->sc_errors = 0;
+       overflows = sc->sc_overflows;
+       sc->sc_overflows = 0;
+       floods = sc->sc_floods;
+       sc->sc_floods = 0;
+       splx(s);
+       log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
+           sc->sc_dev.dv_xname,
+           overflows, overflows == 1 ? "" : "s",
+           floods, floods == 1 ? "" : "s");
+}
+
+void
+exuart_raisedtr(void *arg)
+{
+       //struct exuart_softc *sc = arg;
+
+       //SET(sc->sc_ucr3, EXUART_CR3_DSR); /* XXX */
+       //bus_space_write_2(sc->sc_iot, sc->sc_ioh, EXUART_UCR3, sc->sc_ucr3);
+}
+
+void
+exuart_softint(void *arg)
+{
+       struct exuart_softc *sc = arg;
+       struct tty *tp;
+       u_int16_t *ibufp;
+       u_int16_t *ibufend;
+       int c;
+       int err;
+       int s;
+
+       if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
+               return;
+
+       tp = sc->sc_tty;
+       s = spltty();
+
+       ibufp = sc->sc_ibuf;
+       ibufend = sc->sc_ibufp;
+
+       if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
+               splx(s);
+               return;
+       }
+
+       sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
+           sc->sc_ibufs[1] : sc->sc_ibufs[0];
+       sc->sc_ibufhigh = sc->sc_ibuf + EXUART_IHIGHWATER;
+       sc->sc_ibufend = sc->sc_ibuf + EXUART_IBUFSIZE;
+
+#if 0
+       if (ISSET(tp->t_cflag, CRTSCTS) &&
+           !ISSET(sc->sc_ucr3, EXUART_CR3_DSR)) {
+               /* XXX */
+               SET(sc->sc_ucr3, EXUART_CR3_DSR);
+               bus_space_write_2(sc->sc_iot, sc->sc_ioh, EXUART_UCR3,
+                   sc->sc_ucr3);
+       }
+#endif
+
+       splx(s);
+
+       while (ibufp < ibufend) {
+               c = *ibufp++;
+               if (ISSET(c, EXUART_UERSTAT_OVERRUN)) {
+                       sc->sc_overflows++;
+                       if (sc->sc_errors++ == 0)
+                               timeout_add(&sc->sc_diag_tmo, 60 * hz);
+               }
+               /* This is ugly, but fast. */
+
+               err = 0;
+               if (ISSET(c, EXUART_UERSTAT_PARITY))
+                       err |= TTY_PE;
+               if (ISSET(c, EXUART_UERSTAT_FRAME))
+                       err |= TTY_FE;
+               c = (c & 0xff) | err;
+               (*linesw[tp->t_line].l_rint)(c, tp);
+       }
+}
+
+int
+exuartopen(dev_t dev, int flag, int mode, struct proc *p)
+{
+       int unit = DEVUNIT(dev);
+       struct exuart_softc *sc;
+       bus_space_tag_t iot;
+       bus_space_handle_t ioh;
+       struct tty *tp;
+       int s;
+       int error = 0;
+
+       if (unit >= exuart_cd.cd_ndevs)
+               return ENXIO;
+       sc = exuart_cd.cd_devs[unit];
+       if (sc == NULL)
+               return ENXIO;
+
+       s = spltty();
+       if (sc->sc_tty == NULL)
+               tp = sc->sc_tty = ttymalloc(0);
+       else
+               tp = sc->sc_tty;
+
+       splx(s);
+
+       tp->t_oproc = exuart_start;
+       tp->t_param = exuart_param;
+       tp->t_dev = dev;
+
+       if (!ISSET(tp->t_state, TS_ISOPEN)) {
+               SET(tp->t_state, TS_WOPEN);
+               ttychars(tp);
+               tp->t_iflag = TTYDEF_IFLAG;
+               tp->t_oflag = TTYDEF_OFLAG;
+
+               if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
+                       tp->t_cflag = exuartconscflag;
+               else
+                       tp->t_cflag = TTYDEF_CFLAG;
+               if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
+                       SET(tp->t_cflag, CLOCAL);
+               if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
+                       SET(tp->t_cflag, CRTSCTS);
+               if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
+                       SET(tp->t_cflag, MDMBUF);
+               tp->t_lflag = TTYDEF_LFLAG;
+               tp->t_ispeed = tp->t_ospeed = exuartdefaultrate;
+
+               s = spltty();
+
+               sc->sc_initialize = 1;
+               exuart_param(tp, &tp->t_termios);
+               ttsetwater(tp);
+               sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
+               sc->sc_ibufhigh = sc->sc_ibuf + EXUART_IHIGHWATER;
+               sc->sc_ibufend = sc->sc_ibuf + EXUART_IBUFSIZE;
+
+               iot = sc->sc_iot;
+               ioh = sc->sc_ioh;
+
+               sc->sc_ulcon = bus_space_read_4(iot, ioh, EXUART_ULCON);
+               sc->sc_ucon = bus_space_read_4(iot, ioh, EXUART_UCON);
+               sc->sc_ufcon = bus_space_read_4(iot, ioh, EXUART_UFCON);
+               sc->sc_umcon = bus_space_read_4(iot, ioh, EXUART_UMCON);
+
+#if 0
+               /* interrupt after one char on tx/rx */
+               /* reference frequency divider: 1 */
+               bus_space_write_2(iot, ioh, EXUART_UFCR,
+                   1 << EXUART_FCR_TXTL_SH |
+                   5 << EXUART_FCR_RFDIV_SH |
+                   1 << EXUART_FCR_RXTL_SH);
+
+               bus_space_write_2(iot, ioh, EXUART_UBIR,
+                   (exuartdefaultrate / 100) - 1);
+
+               /* formula: clk / (rfdiv * 1600) */
+               bus_space_write_2(iot, ioh, EXUART_UBMR,
+                   (exccm_get_uartclk() * 1000) / 1600);
+
+               SET(sc->sc_ucr1, EXUART_CR1_EN|EXUART_CR1_RRDYEN);
+               SET(sc->sc_ucr2, EXUART_CR2_TXEN|EXUART_CR2_RXEN);
+               bus_space_write_2(iot, ioh, EXUART_UCR1, sc->sc_ucr1);
+               bus_space_write_2(iot, ioh, EXUART_UCR2, sc->sc_ucr2);
+
+               /* sc->sc_mcr = MCR_DTR | MCR_RTS;  XXX */
+               SET(sc->sc_ucr3, EXUART_CR3_DSR); /* XXX */
+               bus_space_write_2(iot, ioh, EXUART_UCR3, sc->sc_ucr3);
+#endif
+
+               SET(tp->t_state, TS_CARR_ON); /* XXX */
+
+
+       } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0)
+               return EBUSY;
+       else
+               s = spltty();
+
+       if (DEVCUA(dev)) {
+               if (ISSET(tp->t_state, TS_ISOPEN)) {
+                       splx(s);
+                       return EBUSY;
+               }
+               sc->sc_cua = 1;
+       } else {
+               /* tty (not cua) device; wait for carrier if necessary */
+               if (ISSET(flag, O_NONBLOCK)) {
+                       if (sc->sc_cua) {
+                               /* Opening TTY non-blocking... but the CUA is busy */
+                               splx(s);
+                               return EBUSY;
+                       }
+               } else {
+                       while (sc->sc_cua ||
+                           (!ISSET(tp->t_cflag, CLOCAL) &&
+                               !ISSET(tp->t_state, TS_CARR_ON))) {
+                               SET(tp->t_state, TS_WOPEN);
+                               error = ttysleep(tp, &tp->t_rawq,
+                                   TTIPRI | PCATCH, ttopen, 0);
+                               /*
+                                * If TS_WOPEN has been reset, that means the
+                                * cua device has been closed.  We don't want
+                                * to fail in that case,
+                                * so just go around again.
+                                */
+                               if (error && ISSET(tp->t_state, TS_WOPEN)) {
+                                       CLR(tp->t_state, TS_WOPEN);
+                                       if (!sc->sc_cua && !ISSET(tp->t_state,
+                                           TS_ISOPEN))
+                                               exuart_pwroff(sc);
+                                       splx(s);
+                                       return error;
+                               }
+                       }
+               }
+       }
+       splx(s);
+       return (*linesw[tp->t_line].l_open)(dev,tp,p);
+}
+
+int
+exuartclose(dev_t dev, int flag, int mode, struct proc *p)
+{
+       int unit = DEVUNIT(dev);
+       struct exuart_softc *sc = exuart_cd.cd_devs[unit];
+       //bus_space_tag_t iot = sc->sc_iot;
+       //bus_space_handle_t ioh = sc->sc_ioh;
+       struct tty *tp = sc->sc_tty;
+       int s;
+
+       /* XXX This is for cons.c. */
+       if (!ISSET(tp->t_state, TS_ISOPEN))
+               return 0;
+
+       (*linesw[tp->t_line].l_close)(tp, flag, p);
+       s = spltty();
+       if (ISSET(tp->t_state, TS_WOPEN)) {
+               /* tty device is waiting for carrier; drop dtr then re-raise */
+               //CLR(sc->sc_ucr3, EXUART_CR3_DSR);
+               //bus_space_write_2(iot, ioh, EXUART_UCR3, sc->sc_ucr3);
+               timeout_add(&sc->sc_dtr_tmo, hz * 2);
+       } else {
+               /* no one else waiting; turn off the uart */
+               exuart_pwroff(sc);
+       }
+       CLR(tp->t_state, TS_BUSY | TS_FLUSH);
+
+       sc->sc_cua = 0;
+       splx(s);
+       ttyclose(tp);
+
+       return 0;
+}
+
+int
+exuartread(dev_t dev, struct uio *uio, int flag)
+{
+       struct tty *tty;
+
+       tty = exuarttty(dev);
+       if (tty == NULL)
+               return ENODEV;
+
+       return((*linesw[tty->t_line].l_read)(tty, uio, flag));
+}
+
+int
+exuartwrite(dev_t dev, struct uio *uio, int flag)
+{
+       struct tty *tty;
+
+       tty = exuarttty(dev);
+       if (tty == NULL)
+               return ENODEV;
+
+       return((*linesw[tty->t_line].l_write)(tty, uio, flag));
+}
+
+int
+exuartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+       struct exuart_softc *sc;
+       struct tty *tp;
+       int error;
+
+       sc = exuart_sc(dev);
+       if (sc == NULL)
+               return (ENODEV);
+
+       tp = sc->sc_tty;
+       if (tp == NULL)
+               return (ENXIO);
+
+       error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
+       if (error >= 0)
+               return (error);
+
+       error = ttioctl(tp, cmd, data, flag, p);
+       if (error >= 0)
+               return (error);
+
+       switch(cmd) {
+       case TIOCSBRK:
+               /* */
+               break;
+
+       case TIOCCBRK:
+               /* */
+               break;
+
+       case TIOCSDTR:
+#if 0
+               (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
+#endif
+               break;
+
+       case TIOCCDTR:
+#if 0
+               (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
+#endif
+               break;
+
+       case TIOCMSET:
+#if 0
+               (void) clmctl(dev, *(int *) data, DMSET);
+#endif
+               break;
+
+       case TIOCMBIS:
+#if 0
+               (void) clmctl(dev, *(int *) data, DMBIS);
+#endif
+               break;
+
+       case TIOCMBIC:
+#if 0
+               (void) clmctl(dev, *(int *) data, DMBIC);
+#endif
+               break;
+
+        case TIOCMGET:
+#if 0
+               *(int *)data = clmctl(dev, 0, DMGET);
+#endif
+               break;
+
+       case TIOCGFLAGS:
+#if 0
+               *(int *)data = cl->cl_swflags;
+#endif
+               break;
+
+       case TIOCSFLAGS:
+               error = suser(p, 0);
+               if (error != 0)
+                       return(EPERM);
+
+#if 0
+               cl->cl_swflags = *(int *)data;
+               cl->cl_swflags &= /* only allow valid flags */
+                   (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
+#endif
+               break;
+       default:
+               return (ENOTTY);
+       }
+
+       return 0;
+}
+
+int
+exuartstop(struct tty *tp, int flag)
+{
+       return 0;
+}
+
+struct tty *
+exuarttty(dev_t dev)
+{
+       int unit;
+       struct exuart_softc *sc;
+       unit = DEVUNIT(dev);
+       if (unit >= exuart_cd.cd_ndevs)
+               return NULL;
+       sc = (struct exuart_softc *)exuart_cd.cd_devs[unit];
+       if (sc == NULL)
+               return NULL;
+       return sc->sc_tty;
+}
+
+struct exuart_softc *
+exuart_sc(dev_t dev)
+{
+       int unit;
+       struct exuart_softc *sc;
+       unit = DEVUNIT(dev);
+       if (unit >= exuart_cd.cd_ndevs)
+               return NULL;
+       sc = (struct exuart_softc *)exuart_cd.cd_devs[unit];
+       return sc;
+}
+
+
+/* serial console */
+void
+exuartcnprobe(struct consdev *cp)
+{
+       cp->cn_dev = makedev(12 /* XXX */, 0);
+       cp->cn_pri = CN_MIDPRI;
+}
+
+void
+exuartcninit(struct consdev *cp)
+{
+}
+
+int
+exuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag)
+{
+       static struct consdev exuartcons = {
+               NULL, NULL, exuartcngetc, exuartcnputc, exuartcnpollc, NULL,
+               NODEV, CN_MIDPRI
+       };
+
+       if (bus_space_map(iot, iobase, 0x100, 0, &exuartconsioh))
+                       return ENOMEM;
+
+       cn_tab = &exuartcons;
+       cn_tab->cn_dev = makedev(12 /* XXX */, 0);
+       cdevsw[12] = exuartdev;         /* KLUDGE */
+
+       exuartconsiot = iot;
+       exuartconsaddr = iobase;
+       exuartconscflag = cflag;
+
+       return 0;
+}
+
+int
+exuartcngetc(dev_t dev)
+{
+       int c;
+       int s;
+       s = splhigh();
+       while((bus_space_read_4(exuartconsiot, exuartconsioh, EXUART_UTRSTAT) &
+           EXUART_UTRSTAT_RXBREADY) == 0 &&
+             (bus_space_read_4(exuartconsiot, exuartconsioh, EXUART_UFSTAT) &
+           (EXUART_UFSTAT_RX_FIFO_CNT_MASK|EXUART_UFSTAT_RX_FIFO_FULL)) == 0)
+               ;
+       c = bus_space_read_1(exuartconsiot, exuartconsioh, EXUART_URXH);
+       splx(s);
+       return c;
+}
+
+void
+exuartcnputc(dev_t dev, int c)
+{
+       int s;
+       s = splhigh();
+       bus_space_write_1(exuartconsiot, exuartconsioh, EXUART_UTXH, (uint8_t)c);
+       while((bus_space_read_2(exuartconsiot, exuartconsioh, EXUART_UTRSTAT) &
+           EXUART_UTRSTAT_TXBEMPTY) != 0 &&
+             (bus_space_read_2(exuartconsiot, exuartconsioh, EXUART_UFSTAT) &
+           (EXUART_UFSTAT_TX_FIFO_CNT_MASK|EXUART_UFSTAT_TX_FIFO_FULL)) != 0)
+               ;
+       splx(s);
+}
+
+void
+exuartcnpollc(dev_t dev, int on)
+{
+}
diff --git a/sys/arch/armv7/exynos/exuartreg.h b/sys/arch/armv7/exynos/exuartreg.h
new file mode 100644 (file)
index 0000000..37948af
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define        EXUART_ULCON                            0x00
+#define                EXUART_ULCON_WORD_FIVE                  (0x0 << 0)
+#define                EXUART_ULCON_WORD_SIX                   (0x1 << 0)
+#define                EXUART_ULCON_WORD_SEVEN                 (0x2 << 0)
+#define                EXUART_ULCON_WORD_EIGHT                 (0x3 << 0)
+#define                EXUART_ULCON_WORD_MASK                  (0x3 << 0)
+#define                EXUART_ULCON_STOP_ONE                   (0x0 << 2)
+#define                EXUART_ULCON_STOP_TWO                   (0x1 << 2)
+#define                EXUART_ULCON_PARITY_NONE                (0x0 << 3)
+#define                EXUART_ULCON_PARITY_ODD                 (0x4 << 3)
+#define                EXUART_ULCON_PARITY_EVEN                (0x5 << 3)
+#define                EXUART_ULCON_PARITY_FORCED1             (0x6 << 3)
+#define                EXUART_ULCON_PARITY_FORCED0             (0x7 << 3)
+#define                EXUART_ULCON_PARITY_MASK                (0x7 << 3)
+#define                EXUART_ULCON_INFRARED                   (0x1 << 6)
+#define        EXUART_UCON                             0x04
+#define                EXUART_UCON_RX_IRQORPOLL                (0x1 << 0)
+#define                EXUART_UCON_RX_DMA                      (0x2 << 0)
+#define                EXUART_UCON_TX_IRQORPOLL                (0x1 << 2)
+#define                EXUART_UCON_TX_DMA                      (0x2 << 2)
+#define                EXUART_UCON_SEND_BREAK                  (0x1 << 4)
+#define                EXUART_UCON_LOOPBACK_MODE               (0x1 << 5)
+#define                EXUART_UCON_RX_ERR_STS_INT              (0x1 << 6)
+#define                EXUART_UCON_RX_TIMEOUT                  (0x1 << 7)
+#define                EXUART_UCON_RX_INT_TYPE_PULSE           (0x0 << 8)
+#define                EXUART_UCON_RX_INT_TYPE_LEVEL           (0x1 << 8)
+#define                EXUART_UCON_TX_INT_TYPE_PULSE           (0x0 << 9)
+#define                EXUART_UCON_TX_INT_TYPE_LEVEL           (0x1 << 9)
+#define                EXUART_UCON_RX_TIMEOUT_DMA_SUSPEND      (0x1 << 10)
+#define                EXUART_UCON_RX_TIMEOUT_EMPTY_FIFO       (0x1 << 11)
+#define                EXUART_UCON_RX_TIMEOUT_INTERVAL(x)      (((x) & 0xf) << 12) /* 8 * (x + a) frame time */
+#define                EXUART_UCON_RX_DMA_BURST_1B             (0x0 << 16)
+#define                EXUART_UCON_RX_DMA_BURST_4B             (0x1 << 16)
+#define                EXUART_UCON_RX_DMA_BURST_8B             (0x2 << 16)
+#define                EXUART_UCON_RX_DMA_BURST_16B            (0x3 << 16)
+#define                EXUART_UCON_TX_DMA_BURST_1B             (0x0 << 20)
+#define                EXUART_UCON_TX_DMA_BURST_4B             (0x1 << 20)
+#define                EXUART_UCON_TX_DMA_BURST_8B             (0x2 << 20)
+#define                EXUART_UCON_TX_DMA_BURST_16B            (0x3 << 20)
+#define        EXUART_UFCON                            0x08
+#define                EXUART_UFCON_FIFO_ENABLE                (0x1 << 0)
+#define                EXUART_UFCON_RX_FIFO_RESET              (0x1 << 1)
+#define                EXUART_UFCON_TX_FIFO_RESET              (0x1 << 2)
+#define                EXUART_UFCON_RX_FIFO_TRIGGER_LEVEL      (((x) & 0x7) << 4)
+#define                EXUART_UFCON_TX_FIFO_TRIGGER_LEVEL      (((x) & 0x7) << 8)
+#define        EXUART_UMCON                            0x0c
+#define                EXUART_UMCON_RTS                        (0x1 << 0)
+#define                EXUART_UMCON_MODEM_INT_EN               (0x1 << 3)
+#define                EXUART_UMCON_AUTO_FLOW_CONTROL          (0x1 << 4)
+#define                EXUART_UMCON_RTS_TRIGGER_LEVEL          (((x) & 0x7) << 5)
+#define        EXUART_UTRSTAT                          0x10
+#define                EXUART_UTRSTAT_RXBREADY                 (0x1 << 0)
+#define                EXUART_UTRSTAT_TXBEMPTY                 (0x1 << 1)
+#define                EXUART_UTRSTAT_TXEMPTY                  (0x1 << 2)
+#define                EXUART_UTRSTAT_RX_TIMEOUT_STSCLR        (0x1 << 3)
+#define                EXUART_UTRSTAT_RX_DMA_FSM_STS(x)        (((x) >> 8) & 0xf)
+#define                EXUART_UTRSTAT_TX_DMA_FSM_STS(x)        (((x) >> 12) & 0xf)
+#define                EXUART_UTRSTAT_RX_FIFO_CNT_TIMEOUT(x)   (((x) >> 16) & 0xff)
+#define        EXUART_UERSTAT                          0x14
+#define                EXUART_UERSTAT_OVERRUN                  (0x1 << 0)
+#define                EXUART_UERSTAT_PARITY                   (0x1 << 1)
+#define                EXUART_UERSTAT_FRAME                    (0x1 << 2)
+#define                EXUART_UERSTAT_BREAK                    (0x1 << 3)
+#define        EXUART_UFSTAT                           0x18
+#define                EXUART_UFSTAT_RX_FIFO_CNT(x)            (((x) >> 0) & 0xff) /* 0 when full */
+#define                EXUART_UFSTAT_RX_FIFO_CNT_MASK          (0xff << 0) /* 0 when full */
+#define                EXUART_UFSTAT_RX_FIFO_FULL              (0x1 << 8)
+#define                EXUART_UFSTAT_RX_FIFO_ERROR             (0x1 << 9)
+#define                EXUART_UFSTAT_TX_FIFO_CNT(x)            (((x) >> 16) & 0xff) /* 0 when full */
+#define                EXUART_UFSTAT_TX_FIFO_CNT_MASK          (0xff << 16) /* 0 when full */
+#define                EXUART_UFSTAT_TX_FIFO_FULL              (0x1 << 24)
+#define        EXUART_UMSTAT                           0x1c
+#define                EXUART_UMSTAT_CTS                       (0x1 << 0)
+#define                EXUART_UMSTAT_DELTA_CTS                 (0x1 << 4)
+#define        EXUART_UTXH                             0x20
+#define        EXUART_URXH                             0x24
+#define        EXUART_UBRDIV                           0x28
+#define                EXUART_UBRDIV_SEL(x)                    (((x) & 0xffff) << 0)
+#define        EXUART_UFRACVAL                         0x2c
+#define                EXUART_UFRACVAL_SEL(x)                  (((x) & 0xf) << 0)
+#define        EXUART_UINTP                            0x30
+#define                EXUART_UINTP_RXD                        (0x1 << 0)
+#define                EXUART_UINTP_ERROR                      (0x1 << 1)
+#define                EXUART_UINTP_TXD                        (0x1 << 2)
+#define                EXUART_UINTP_MODEM                      (0x1 << 3)
+#define        EXUART_UINTS                            0x34
+#define                EXUART_UINTS_RXD                        (0x1 << 0)
+#define                EXUART_UINTS_ERROR                      (0x1 << 1)
+#define                EXUART_UINTS_TXD                        (0x1 << 2)
+#define                EXUART_UINTS_MODEM                      (0x1 << 3)
+#define        EXUART_UINTM                            0x38
+#define                EXUART_UINTM_RXD                        (0x1 << 0)
+#define                EXUART_UINTM_ERROR                      (0x1 << 1)
+#define                EXUART_UINTM_TXD                        (0x1 << 2)
+#define                EXUART_UINTM_MODEM                      (0x1 << 3)
diff --git a/sys/arch/armv7/exynos/exuartvar.h b/sys/arch/armv7/exynos/exuartvar.h
new file mode 100644 (file)
index 0000000..f331f6f
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2005 Dale Rahn <drahn@motorola.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+int exuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
+    tcflag_t cflag);
diff --git a/sys/arch/armv7/exynos/exynos.c b/sys/arch/armv7/exynos/exynos.c
new file mode 100644 (file)
index 0000000..dc37063
--- /dev/null
@@ -0,0 +1,71 @@
+/* $OpenBSD: exynos.c,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
+/*
+ * Copyright (c) 2005,2008 Dale Rahn <drahn@openbsd.com>
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <armv7/armv7/armv7var.h>
+
+static int
+exynos_match(struct device *parent, void *cfdata, void *aux)
+{
+       /* If we're running with fdt, do not attach. */
+       /* XXX: Find a better way. */
+       if (fdt_next_node(0))
+               return (0);
+
+       switch (board_id)
+       {
+       case BOARD_ID_EXYNOS5_CHROMEBOOK:
+               return (1);
+       }
+
+       return (0);
+}
+
+struct cfattach exynos_ca = {
+       sizeof(struct armv7_softc), exynos_match, armv7_attach, NULL,
+       config_activate_children
+};
+
+struct cfdriver exynos_cd = {
+       NULL, "exynos", DV_DULL
+};
+
+struct board_dev chromebook_devs[] = {
+       { "exmct",      0 },
+       { "exdog",      0 },
+       { "exclock",    0 },
+       { "expower",    0 },
+       { "exsysreg",   0 },
+//     { "exuart",     1 },
+       { "exgpio",     0 },
+       { "exgpio",     1 },
+       { "exgpio",     2 },
+       { "exgpio",     3 },
+       { "exgpio",     4 },
+       { "exgpio",     5 },
+       { "exehci",     0 },
+       { "exiic",      4 },
+//     { "exesdhc",    2 },
+//     { "exesdhc",    3 },
+       { NULL,         0 }
+};
diff --git a/sys/arch/armv7/exynos/exynos5.c b/sys/arch/armv7/exynos/exynos5.c
new file mode 100644 (file)
index 0000000..261b33b
--- /dev/null
@@ -0,0 +1,324 @@
+/* $OpenBSD: exynos5.c,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
+/*
+ * Copyright (c) 2011 Uwe Stuehler <uwe@openbsd.org>
+ * Copyright (c) 2012 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <machine/bus.h>
+#include <arch/arm/armv7/armv7var.h>
+
+#include <armv7/armv7/armv7var.h>
+
+/* XXX ??? */
+/* IRQs are defined without the 32 cpu IRQs */
+
+#define MCT_ADDR       0x101c0000
+#define MCT_SIZE       0x1000
+
+#define WD_ADDR                0x101d0000
+#define WD_SIZE                0x400
+
+#define CLOCK_ADDR     0x10010000
+#define CLOCK_SIZE     0x5000
+
+#define POWER_ADDR     0x10040000
+#define POWER_SIZE     0x1000
+
+#define SYSREG_ADDR    0x10050000
+#define SYSREG_SIZE    0x1000
+
+#define UARTx_SIZE     0x100
+#define UART1_ADDR     0x12c00000
+#define UART2_ADDR     0x12c10000
+#define UART3_ADDR     0x12c20000
+#define UART4_ADDR     0x12c30000
+
+#define UART1_IRQ      83
+#define UART2_IRQ      84
+#define UART3_IRQ      85
+#define UART4_IRQ      86
+
+#define USB_EHCI_ADDR  0x12110000
+#define USB_PHY_ADDR   0x12130000
+#define USBx_SIZE      0x1000
+
+#define USB_IRQ                71
+
+#define GPIO1_ADDR     0x11400000
+#define GPIO1_SIZE     0x280
+#define GPIO2_ADDR     0x11400C00
+#define GPIO2_SIZE     0x80
+#define GPIO3_ADDR     0x13400000
+#define GPIO3_SIZE     0x120
+#define GPIO4_ADDR     0x10D10000
+#define GPIO4_SIZE     0x80
+#define GPIO5_ADDR     0x10D100C0
+#define GPIO5_SIZE     0x20
+#define GPIO6_ADDR     0x03860000
+#define GPIO6_SIZE     0x20
+
+#define I2Cx_SIZE      0x100
+#define I2C1_ADDR      0x12c60000
+#define I2C2_ADDR      0x12c70000
+#define I2C3_ADDR      0x12c80000
+#define I2C4_ADDR      0x12c90000
+#define I2C5_ADDR      0x12ca0000
+#define I2C6_ADDR      0x12cb0000
+#define I2C7_ADDR      0x12cc0000
+#define I2C8_ADDR      0x12cd0000
+
+#define I2C1_IRQ       56
+#define I2C2_IRQ       57
+#define I2C3_IRQ       58
+#define I2C4_IRQ       59
+#define I2C5_IRQ       60
+#define I2C6_IRQ       61
+#define I2C7_IRQ       62
+#define I2C8_IRQ       63
+
+#define ESDHCx_SIZE    0x1000
+#define ESDHC1_ADDR    0x12200000
+#define ESDHC2_ADDR    0x12210000
+#define ESDHC3_ADDR    0x12220000
+#define ESDHC4_ADDR    0x12230000
+
+#define ESDHC1_IRQ     75
+#define ESDHC2_IRQ     76
+#define ESDHC3_IRQ     77
+#define ESDHC4_IRQ     78
+
+#define PCIE_REG_ADDR  0x01ffc000
+#define PCIE_REG_SIZE  0x4000
+#define PCIE_MAP_ADDR  0x01000000
+#define PCIE_MAP_SIZE  0xffc000
+
+#define PCIE_IRQ0      120
+#define PCIE_IRQ1      121
+#define PCIE_IRQ2      122
+#define PCIE_IRQ3      123
+
+struct armv7_dev exynos5_devs[] = {
+
+       /*
+        * Multi-Core Timer
+        */
+       { .name = "exmct",
+         .unit = 0,
+         .mem = {
+           { MCT_ADDR, MCT_SIZE },
+         },
+       },
+
+       /*
+        * Watchdog Timer
+        */
+       { .name = "exdog",
+         .unit = 0,
+         .mem = {
+           { WD_ADDR, WD_SIZE },
+         },
+       },
+
+       /*
+        * Clock
+        */
+       { .name = "exclock",
+         .unit = 0,
+         .mem = {
+           { CLOCK_ADDR, CLOCK_SIZE },
+         },
+       },
+
+       /*
+        * Power
+        */
+       { .name = "expower",
+         .unit = 0,
+         .mem = {
+           { POWER_ADDR, POWER_SIZE },
+         },
+       },
+
+       /*
+        * Sysreg
+        */
+       { .name = "exsysreg",
+         .unit = 0,
+         .mem = {
+           { SYSREG_ADDR, SYSREG_SIZE },
+         },
+       },
+
+       /*
+        * UART
+        */
+       { .name = "exuart",
+         .unit = 0,
+         .mem = { { UART1_ADDR, UARTx_SIZE } },
+         .irq = { UART1_IRQ }
+       },
+       { .name = "exuart",
+         .unit = 1,
+         .mem = { { UART2_ADDR, UARTx_SIZE } },
+         .irq = { UART2_IRQ }
+       },
+       { .name = "exuart",
+         .unit = 2,
+         .mem = { { UART3_ADDR, UARTx_SIZE } },
+         .irq = { UART3_IRQ }
+       },
+       { .name = "exuart",
+         .unit = 3,
+         .mem = { { UART4_ADDR, UARTx_SIZE } },
+         .irq = { UART4_IRQ }
+       },
+
+       /*
+        * GPIO
+        */
+       { .name = "exgpio",
+         .unit = 0,
+         .mem = { { GPIO1_ADDR, GPIO1_SIZE } },
+       },
+
+       { .name = "exgpio",
+         .unit = 1,
+         .mem = { { GPIO2_ADDR, GPIO2_SIZE } },
+       },
+
+       { .name = "exgpio",
+         .unit = 2,
+         .mem = { { GPIO3_ADDR, GPIO3_SIZE } },
+       },
+
+       { .name = "exgpio",
+         .unit = 3,
+         .mem = { { GPIO4_ADDR, GPIO4_SIZE } },
+       },
+
+       { .name = "exgpio",
+         .unit = 4,
+         .mem = { { GPIO5_ADDR, GPIO5_SIZE } },
+       },
+
+       { .name = "exgpio",
+         .unit = 5,
+         .mem = { { GPIO6_ADDR, GPIO6_SIZE } },
+       },
+
+       /*
+        * I2C
+        */
+       { .name = "exiic",
+         .unit = 0,
+         .mem = { { I2C1_ADDR, I2Cx_SIZE } },
+         .irq = { I2C1_IRQ },
+       },
+
+       { .name = "exiic",
+         .unit = 1,
+         .mem = { { I2C2_ADDR, I2Cx_SIZE } },
+         .irq = { I2C2_IRQ },
+       },
+
+       { .name = "exiic",
+         .unit = 2,
+         .mem = { { I2C3_ADDR, I2Cx_SIZE } },
+         .irq = { I2C3_IRQ },
+       },
+
+       { .name = "exiic",
+         .unit = 3,
+         .mem = { { I2C4_ADDR, I2Cx_SIZE } },
+         .irq = { I2C4_IRQ },
+       },
+
+       { .name = "exiic",
+         .unit = 4,
+         .mem = { { I2C5_ADDR, I2Cx_SIZE } },
+         .irq = { I2C5_IRQ },
+       },
+
+       { .name = "exiic",
+         .unit = 5,
+         .mem = { { I2C6_ADDR, I2Cx_SIZE } },
+         .irq = { I2C6_IRQ },
+       },
+
+       { .name = "exiic",
+         .unit = 6,
+         .mem = { { I2C7_ADDR, I2Cx_SIZE } },
+         .irq = { I2C7_IRQ },
+       },
+
+       { .name = "exiic",
+         .unit = 7,
+         .mem = { { I2C8_ADDR, I2Cx_SIZE } },
+         .irq = { I2C8_IRQ },
+       },
+
+       /*
+        * ESDHC
+        */
+       { .name = "exesdhc",
+         .unit = 0,
+         .mem = { { ESDHC1_ADDR, ESDHCx_SIZE } },
+         .irq = { ESDHC1_IRQ },
+       },
+
+       { .name = "exesdhc",
+         .unit = 1,
+         .mem = { { ESDHC2_ADDR, ESDHCx_SIZE } },
+         .irq = { ESDHC2_IRQ },
+       },
+
+       { .name = "exesdhc",
+         .unit = 2,
+         .mem = { { ESDHC3_ADDR, ESDHCx_SIZE } },
+         .irq = { ESDHC3_IRQ },
+       },
+
+       { .name = "exesdhc",
+         .unit = 3,
+         .mem = { { ESDHC4_ADDR, ESDHCx_SIZE } },
+         .irq = { ESDHC4_IRQ },
+       },
+
+       /*
+        * USB
+        */
+       { .name = "exehci",
+         .unit = 0,
+         .mem = {
+           { USB_EHCI_ADDR, USBx_SIZE },
+           { USB_PHY_ADDR, USBx_SIZE },
+         },
+         .irq = { USB_IRQ }
+       },
+
+       /* Terminator */
+       { .name = NULL,
+         .unit = 0
+       }
+};
+
+void
+exynos5_init(void)
+{
+       armv7_set_devs(exynos5_devs);
+}
diff --git a/sys/arch/armv7/exynos/exynos_machdep.c b/sys/arch/armv7/exynos/exynos_machdep.c
new file mode 100644 (file)
index 0000000..aff9bf3
--- /dev/null
@@ -0,0 +1,109 @@
+/*     $OpenBSD        */
+/*
+ * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/termios.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <arm/cortex/smc.h>
+#include <arm/armv7/armv7var.h>
+#include <armv7/armv7/armv7var.h>
+#include <armv7/exynos/exdisplayvar.h>
+#include <armv7/armv7/armv7_machdep.h>
+
+extern void exdog_reset(void);
+extern int32_t agtimer_frequency;
+extern int comcnspeed;
+extern int comcnmode;
+
+static void
+exynos_platform_smc_write(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off,
+    uint32_t op, uint32_t val)
+{
+       bus_space_write_4(iot, ioh, off, val);
+}
+
+static void
+exynos_platform_init_cons(void)
+{
+       paddr_t paddr;
+       size_t size;
+       void *node;
+
+       switch (board_id) {
+       case BOARD_ID_EXYNOS5_CHROMEBOOK:
+               node = fdt_find_node("/framebuffer");
+               if (node != NULL) {
+                       uint32_t *mem;
+                       if (fdt_node_property(node, "reg", (char **)&mem) >= 2*sizeof(uint32_t)) {
+                               paddr = betoh32(*mem++);
+                               size = betoh32(*mem);
+                       }
+               }
+               exdisplay_cnattach(&armv7_bs_tag, paddr, size);
+               break;
+       default:
+               printf("board type %x unknown", board_id);
+               return;
+               /* XXX - HELP */
+       }
+}
+
+static void
+exynos_platform_watchdog_reset(void)
+{
+       exdog_reset();
+}
+
+static void
+exynos_platform_powerdown(void)
+{
+
+}
+
+static void
+exynos_platform_print_board_type(void)
+{
+       switch (board_id) {
+       case BOARD_ID_EXYNOS5_CHROMEBOOK:
+               agtimer_frequency = 24 * 1000 * 1000;
+               printf("board type: Exynos 5 Chromebook\n");
+               break;
+       default:
+               printf("board type %x unknown\n", board_id);
+       }
+}
+
+static void
+exynos_platform_disable_l2_if_needed(void)
+{
+
+}
+
+struct armv7_platform exynos_platform = {
+       .boot_name = "OpenBSD/exynos",
+       .smc_write = exynos_platform_smc_write,
+       .init_cons = exynos_platform_init_cons,
+       .watchdog_reset = exynos_platform_watchdog_reset,
+       .powerdown = exynos_platform_powerdown,
+       .print_board_type = exynos_platform_print_board_type,
+       .disable_l2_if_needed = exynos_platform_disable_l2_if_needed,
+};
diff --git a/sys/arch/armv7/exynos/files.exynos b/sys/arch/armv7/exynos/files.exynos
new file mode 100644 (file)
index 0000000..48f571d
--- /dev/null
@@ -0,0 +1,74 @@
+#      $OpenBSD: files.exynos,v 1.1 2015/01/26 02:48:24 bmercer Exp $
+
+define exynos {}
+device exynos: exynos
+attach exynos at mainbus
+file   arch/armv7/exynos/exynos_machdep.c      exynos  needs-flag
+file   arch/armv7/exynos/exynos.c              exynos
+file   arch/armv7/exynos/exynos5.c             exynos
+
+# serial ports
+device exuart
+attach exuart at exynos
+attach exuart at fdt with exuart_fdt
+file   arch/armv7/exynos/exuart.c              exuart | exuart_fdt
+
+device exdisplay: wsemuldisplaydev, rasops16
+attach exdisplay at exynos
+attach exdisplay at fdt with exdisplay_fdt
+file   arch/armv7/exynos/exdisplay.c           exdisplay | exdisplay_fdt
+
+device exclock
+attach exclock at exynos
+attach exclock at fdt with exclock_fdt
+file   arch/armv7/exynos/exclock.c             exclock | exclock_fdt
+
+device expower
+attach expower at exynos
+attach expower at fdt with expower_fdt
+file   arch/armv7/exynos/expower.c             expower | expower_fdt
+
+device exsysreg
+attach exsysreg at exynos
+attach exsysreg at fdt with exsysreg_fdt
+file   arch/armv7/exynos/exsysreg.c            exsysreg | exsysreg_fdt
+
+device exmct
+attach exmct at exynos
+attach exmct at fdt with exmct_fdt
+file   arch/armv7/exynos/exmct.c               exmct | exiomuxc_fdt
+
+device exdog
+attach exdog at exynos
+attach exdog at fdt with exdog_fdt
+file   arch/armv7/exynos/exdog.c               exdog | exdog_fdt
+
+device exgpio
+attach exgpio at exynos
+attach exgpio at fdt with exgpio_fdt
+file   arch/armv7/exynos/exgpio.c              exgpio | exgpio_fdt
+
+device exiic: i2cbus
+attach exiic at exynos
+attach exiic at fdt with exiic_fdt
+file   arch/armv7/exynos/exiic.c               exiic | exiic_fdt
+
+device exehci {}
+attach exehci at exynos with exehci
+attach exehci at fdt with exehci_fdt
+attach ehci at exehci with ehci_ex
+file   arch/armv7/exynos/exehci.c              exehci | exehci_fdt
+
+device exesdhc: sdmmcbus
+attach exesdhc at exynos
+attach exesdhc at fdt with exesdhc_fdt
+file   arch/armv7/exynos/exesdhc.c             exesdhc | exesdhc_fdt
+
+device crosec: wskbddev
+attach crosec at i2c
+file   arch/armv7/exynos/crosec.c              crosec
+file   arch/armv7/exynos/crosec_kbd.c          crosec
+
+device tpspmic
+attach tpspmic at i2c
+file   arch/armv7/exynos/tps65090.c            tpspmic
diff --git a/sys/arch/armv7/exynos/tps65090.c b/sys/arch/armv7/exynos/tps65090.c
new file mode 100644 (file)
index 0000000..23e4fc9
--- /dev/null
@@ -0,0 +1,225 @@
+/* $OpenBSD: tps65090.c,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */
+/*
+ * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/sensors.h>
+#include <sys/malloc.h>
+
+#include <dev/i2c/i2cvar.h>
+
+#define        REG_IRQ1                0x00
+#define        REG_IRQ2                0x01
+#define        REG_IRQ1MASK            0x02
+#define        REG_IRQ2MASK            0x03
+#define        REG_CG_CTRL0            0x04
+#define         REG_CG_CTRL0_ENC_MASK          (1 << 0)
+#define        REG_CG_CTRL1            0x05
+#define        REG_CG_CTRL2            0x06
+#define        REG_CG_CTRL3            0x07
+#define        REG_CG_CTRL4            0x08
+#define        REG_CG_CTRL5            0x09
+#define        REG_CG_STATUS1          0x0a
+#define        REG_CG_STATUS2          0x0b
+#define        REG_DCDC1_CTRL          0x0c
+#define        REG_DCDC2_CTRL          0x0d
+#define        REG_DCDC3_CTRL          0x0e
+#define        REG_FET1_CTRL           0x0f
+#define        REG_FET2_CTRL           0x10
+#define        REG_FET3_CTRL           0x11
+#define        REG_FET4_CTRL           0x12
+#define        REG_FET5_CTRL           0x13
+#define        REG_FET6_CTRL           0x14
+#define        REG_FET7_CTRL           0x15
+#define        REG_FETx_CTRL(x)        (0x0e + (x))
+#define         REG_FETx_CTRL_ENFET            (1 << 0) /* Enable FET */
+#define         REG_FETx_CTRL_ADENFET          (1 << 1) /* Enable output auto discharge */
+#define         REG_FETx_CTRL_WAIT             (3 << 2) /* Overcurrent timeout max */
+#define         REG_FETx_CTRL_PGFET            (1 << 4) /* Power good for FET status */
+#define         REG_FETx_CTRL_TOFET            (1 << 7) /* Timeout, startup, overload */
+#define        REG_AD_CTRL             0x16
+#define        REG_AD_OUT1             0x17
+#define        REG_AD_OUT2             0x18
+
+#define        NFET                    7
+
+#ifdef DEBUG
+#define DPRINTF(x) printf x
+#else
+#define DPRINTF(x)
+#endif
+
+struct tps65090_softc {
+       struct device           sc_dev;
+       i2c_tag_t sc_tag;
+       i2c_addr_t sc_addr;
+};
+
+struct tps65090_softc *tps65090_sc;
+
+int    tps65090_match(struct device *, void *, void *);
+void   tps65090_attach(struct device *, struct device *, void *);
+
+int    tps65090_read_reg(struct tps65090_softc *, uint8_t);
+void   tps65090_write_reg(struct tps65090_softc *, uint8_t, uint8_t);
+int    tps65090_fet_set(int, int);
+int    tps65090_fet_get(int);
+void   tps65090_fet_enable(int);
+void   tps65090_fet_disable(int);
+int    tps65090_get_charging(void);
+void   tps65090_set_charging(int);
+
+struct cfattach tpspmic_ca = {
+       sizeof(struct tps65090_softc), tps65090_match, tps65090_attach
+};
+
+struct cfdriver tpspmic_cd = {
+       NULL, "tps65090", DV_DULL
+};
+
+int
+tps65090_match(struct device *parent, void *match, void *aux)
+{
+       struct i2c_attach_args *ia = aux;
+
+       if (strcmp(ia->ia_name, "tps65090") == 0)
+               return (1);
+       return (0);
+}
+
+void
+tps65090_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct tps65090_softc *sc = (struct tps65090_softc *)self;
+       struct i2c_attach_args *ia = aux;
+
+       sc->sc_tag = ia->ia_tag;
+       sc->sc_addr = ia->ia_addr;
+       tps65090_sc = sc;
+
+       printf("\n");
+}
+
+/*
+ * FET1: Backlight on the Chromebook
+ * FET6: LCD panel on the Chromebook
+ */
+void
+tps65090_fet_enable(int fet)
+{
+       int i;
+
+       if (fet < 1 || fet > NFET)
+               return;
+
+       for (i = 0; i < 10; i++) {
+               if (!tps65090_fet_set(fet, 1))
+                       break;
+
+               if (i != 9)
+                       tps65090_fet_set(fet, 0);
+       }
+}
+
+void
+tps65090_fet_disable(int fet)
+{
+       if (fet < 1 || fet > NFET)
+               return;
+
+       tps65090_fet_set(fet, 0);
+}
+
+int
+tps65090_fet_set(int fet, int set)
+{
+       struct tps65090_softc *sc = tps65090_sc;
+       int i;
+       uint8_t val, check;
+
+       val = REG_FETx_CTRL_ADENFET | REG_FETx_CTRL_WAIT;
+       if (set)
+               val |= REG_FETx_CTRL_ENFET;
+
+       tps65090_write_reg(sc, REG_FETx_CTRL(fet), val);
+       for (i = 0; i < 5; i++) {
+               check = tps65090_read_reg(sc, REG_FETx_CTRL(fet));
+
+               /* FET state correct? */
+               if (!!(check & REG_FETx_CTRL_PGFET) == set)
+                       return 0;
+
+               /* Timeout, don't need to try again. */
+               if (check & REG_FETx_CTRL_TOFET)
+                       break;
+
+               delay(1000);
+       }
+
+       return -1;
+}
+
+int
+tps65090_fet_get(int fet)
+{
+       struct tps65090_softc *sc = tps65090_sc;
+       uint8_t val = tps65090_read_reg(sc, REG_FETx_CTRL(fet));
+       return val & REG_FETx_CTRL_ENFET;
+}
+
+int
+tps65090_get_charging()
+{
+       struct tps65090_softc *sc = tps65090_sc;
+       uint8_t val = tps65090_read_reg(sc, REG_CG_CTRL0);
+       return val & REG_CG_CTRL0_ENC_MASK;
+}
+
+void
+tps65090_set_charging(int set)
+{
+       struct tps65090_softc *sc = tps65090_sc;
+       uint8_t val = tps65090_read_reg(sc, REG_CG_CTRL0);
+       if (set)
+               val |= REG_CG_CTRL0_ENC_MASK;
+       else
+               val &= REG_CG_CTRL0_ENC_MASK;
+       tps65090_write_reg(sc, REG_CG_CTRL0, val);
+}
+
+int
+tps65090_read_reg(struct tps65090_softc *sc, uint8_t cmd)
+{
+       uint8_t val;
+
+       iic_acquire_bus(sc->sc_tag, 0);
+       iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+           sc->sc_addr, &cmd, 1, &val, 1, 0);
+       iic_release_bus(sc->sc_tag, 0);
+
+       return val;
+}
+
+void
+tps65090_write_reg(struct tps65090_softc *sc, uint8_t cmd, uint8_t val)
+{
+       iic_acquire_bus(sc->sc_tag, 0);
+       iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
+           sc->sc_addr, &cmd, 1, &val, 1, 0);
+       iic_release_bus(sc->sc_tag, 0);
+}