summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrandon Mercer <bmercer@cvs.openbsd.org>2015-01-26 02:48:25 +0000
committerBrandon Mercer <bmercer@cvs.openbsd.org>2015-01-26 02:48:25 +0000
commit34a8368bc8175eb2a24ea327ff945835ca6e9fd7 (patch)
tree4b8275ea7f46530e8f70b212bc76e20c17ac639c
parent5c9fb779da79fd7e7451055c874fc31295b22d06 (diff)
Import the exynos work into tree. This is from Bitrig. Discussed with and OK jsg, also OK from krw.
-rw-r--r--sys/arch/armv7/exynos/crosec.c274
-rw-r--r--sys/arch/armv7/exynos/crosec_kbd.c249
-rw-r--r--sys/arch/armv7/exynos/crosecvar.h61
-rw-r--r--sys/arch/armv7/exynos/ec_commands.h1500
-rw-r--r--sys/arch/armv7/exynos/exclock.c300
-rw-r--r--sys/arch/armv7/exynos/exclockvar.h23
-rw-r--r--sys/arch/armv7/exynos/exdisplay.c290
-rw-r--r--sys/arch/armv7/exynos/exdisplayvar.h17
-rw-r--r--sys/arch/armv7/exynos/exdog.c146
-rw-r--r--sys/arch/armv7/exynos/exehci.c321
-rw-r--r--sys/arch/armv7/exynos/exesdhc.c990
-rw-r--r--sys/arch/armv7/exynos/exgpio.c283
-rw-r--r--sys/arch/armv7/exynos/exgpiovar.h41
-rw-r--r--sys/arch/armv7/exynos/exiic.c430
-rw-r--r--sys/arch/armv7/exynos/exiicvar.h27
-rw-r--r--sys/arch/armv7/exynos/exmct.c117
-rw-r--r--sys/arch/armv7/exynos/expower.c114
-rw-r--r--sys/arch/armv7/exynos/expowervar.h23
-rw-r--r--sys/arch/armv7/exynos/exsysreg.c114
-rw-r--r--sys/arch/armv7/exynos/exsysregvar.h23
-rw-r--r--sys/arch/armv7/exynos/exuart.c888
-rw-r--r--sys/arch/armv7/exynos/exuartreg.h111
-rw-r--r--sys/arch/armv7/exynos/exuartvar.h18
-rw-r--r--sys/arch/armv7/exynos/exynos.c71
-rw-r--r--sys/arch/armv7/exynos/exynos5.c324
-rw-r--r--sys/arch/armv7/exynos/exynos_machdep.c109
-rw-r--r--sys/arch/armv7/exynos/files.exynos74
-rw-r--r--sys/arch/armv7/exynos/tps65090.c225
28 files changed, 7163 insertions, 0 deletions
diff --git a/sys/arch/armv7/exynos/crosec.c b/sys/arch/armv7/exynos/crosec.c
new file mode 100644
index 00000000000..21178b48534
--- /dev/null
+++ b/sys/arch/armv7/exynos/crosec.c
@@ -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
index 00000000000..cc8e0151b15
--- /dev/null
+++ b/sys/arch/armv7/exynos/crosec_kbd.c
@@ -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
index 00000000000..1f869c3b83b
--- /dev/null
+++ b/sys/arch/armv7/exynos/crosecvar.h
@@ -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
index 00000000000..8dc2df07133
--- /dev/null
+++ b/sys/arch/armv7/exynos/ec_commands.h
@@ -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
index 00000000000..85f595a9a2e
--- /dev/null
+++ b/sys/arch/armv7/exynos/exclock.c
@@ -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
index 00000000000..a5e3fd7d66f
--- /dev/null
+++ b/sys/arch/armv7/exynos/exclockvar.h
@@ -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
index 00000000000..6c7663faa2d
--- /dev/null
+++ b/sys/arch/armv7/exynos/exdisplay.c
@@ -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
index 00000000000..853e683423d
--- /dev/null
+++ b/sys/arch/armv7/exynos/exdisplayvar.h
@@ -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
index 00000000000..d5e285a49a8
--- /dev/null
+++ b/sys/arch/armv7/exynos/exdog.c
@@ -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
index 00000000000..a73f6284fb3
--- /dev/null
+++ b/sys/arch/armv7/exynos/exehci.c
@@ -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
index 00000000000..2a48896cfab
--- /dev/null
+++ b/sys/arch/armv7/exynos/exesdhc.c
@@ -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
index 00000000000..fa8bbf377b3
--- /dev/null
+++ b/sys/arch/armv7/exynos/exgpio.c
@@ -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
index 00000000000..a53b9fedd3d
--- /dev/null
+++ b/sys/arch/armv7/exynos/exgpiovar.h
@@ -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
index 00000000000..e47f156725e
--- /dev/null
+++ b/sys/arch/armv7/exynos/exiic.c
@@ -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
index 00000000000..8a70257be22
--- /dev/null
+++ b/sys/arch/armv7/exynos/exiicvar.h
@@ -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
index 00000000000..37c71806fdc
--- /dev/null
+++ b/sys/arch/armv7/exynos/exmct.c
@@ -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
index 00000000000..4bb4a2b7fd8
--- /dev/null
+++ b/sys/arch/armv7/exynos/expower.c
@@ -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
index 00000000000..14e41bc3d0d
--- /dev/null
+++ b/sys/arch/armv7/exynos/expowervar.h
@@ -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
index 00000000000..169ecc0d69f
--- /dev/null
+++ b/sys/arch/armv7/exynos/exsysreg.c
@@ -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
index 00000000000..de4bbb0463e
--- /dev/null
+++ b/sys/arch/armv7/exynos/exsysregvar.h
@@ -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
index 00000000000..9e2c1149337
--- /dev/null
+++ b/sys/arch/armv7/exynos/exuart.c
@@ -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
index 00000000000..37948af47db
--- /dev/null
+++ b/sys/arch/armv7/exynos/exuartreg.h
@@ -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
index 00000000000..f331f6f4802
--- /dev/null
+++ b/sys/arch/armv7/exynos/exuartvar.h
@@ -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
index 00000000000..dc370633cc8
--- /dev/null
+++ b/sys/arch/armv7/exynos/exynos.c
@@ -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
index 00000000000..261b33bec5b
--- /dev/null
+++ b/sys/arch/armv7/exynos/exynos5.c
@@ -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
index 00000000000..aff9bf38c13
--- /dev/null
+++ b/sys/arch/armv7/exynos/exynos_machdep.c
@@ -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
index 00000000000..48f571dcef8
--- /dev/null
+++ b/sys/arch/armv7/exynos/files.exynos
@@ -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
index 00000000000..23e4fc9b228
--- /dev/null
+++ b/sys/arch/armv7/exynos/tps65090.c
@@ -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);
+}