diff --git a/sys/arm/samsung/exynos/chrome_kb.c b/sys/arm/samsung/exynos/chrome_kb.c
index d5d55e9233df..b10a5ac8b187 100644
--- a/sys/arm/samsung/exynos/chrome_kb.c
+++ b/sys/arm/samsung/exynos/chrome_kb.c
@@ -1,923 +1,921 @@
/*-
* Copyright (c) 2014 Ruslan Bukin
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Samsung Chromebook Keyboard
*/
#include
__FBSDID("$FreeBSD$");
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
-#include
#include
#include
#include
#include
#include
#include
#include
#include
-#include
#include
#include
#include "gpio_if.h"
#include
#include
#include
#include
#define CKB_LOCK() mtx_lock(&Giant)
#define CKB_UNLOCK() mtx_unlock(&Giant)
#ifdef INVARIANTS
/*
* Assert that the lock is held in all contexts
* where the code can be executed.
*/
#define CKB_LOCK_ASSERT() mtx_assert(&Giant, MA_OWNED)
/*
* Assert that the lock is held in the contexts
* where it really has to be so.
*/
#define CKB_CTX_LOCK_ASSERT() \
do { \
if (!kdb_active && panicstr == NULL) \
mtx_assert(&Giant, MA_OWNED); \
} while (0)
#else
#define CKB_LOCK_ASSERT() (void)0
#define CKB_CTX_LOCK_ASSERT() (void)0
#endif
/*
* Define a stub keyboard driver in case one hasn't been
* compiled into the kernel
*/
#include
#include
#include
#define CKB_NFKEY 12
#define CKB_FLAG_COMPOSE 0x1
#define CKB_FLAG_POLLING 0x2
#define KBD_DRIVER_NAME "ckbd"
struct ckb_softc {
keyboard_t sc_kbd;
keymap_t sc_keymap;
accentmap_t sc_accmap;
fkeytab_t sc_fkeymap[CKB_NFKEY];
struct resource* sc_mem_res;
struct resource* sc_irq_res;
void* sc_intr_hl;
int sc_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */
int sc_state; /* shift/lock key state */
int sc_accents; /* accent key index (> 0) */
int sc_flags; /* flags */
struct callout sc_repeat_callout;
int sc_repeat_key;
int sc_repeating;
int flag;
int rows;
int cols;
int gpio;
device_t dev;
device_t gpio_dev;
struct thread *sc_poll_thread;
uint16_t *keymap;
uint8_t *scan_local;
uint8_t *scan;
};
/* prototypes */
static int ckb_set_typematic(keyboard_t *, int);
static uint32_t ckb_read_char(keyboard_t *, int);
static void ckb_clear_state(keyboard_t *);
static int ckb_ioctl(keyboard_t *, u_long, caddr_t);
static int ckb_enable(keyboard_t *);
static int ckb_disable(keyboard_t *);
static void
ckb_repeat(void *arg)
{
struct ckb_softc *sc;
sc = arg;
if (KBD_IS_ACTIVE(&sc->sc_kbd) && KBD_IS_BUSY(&sc->sc_kbd)) {
if (sc->sc_repeat_key != -1) {
sc->sc_repeating = 1;
sc->sc_kbd.kb_callback.kc_func(&sc->sc_kbd,
KBDIO_KEYINPUT, sc->sc_kbd.kb_callback.kc_arg);
}
}
}
/* detect a keyboard, not used */
static int
ckb__probe(int unit, void *arg, int flags)
{
return (ENXIO);
}
/* reset and initialize the device, not used */
static int
ckb_init(int unit, keyboard_t **kbdp, void *arg, int flags)
{
return (ENXIO);
}
/* test the interface to the device, not used */
static int
ckb_test_if(keyboard_t *kbd)
{
return (0);
}
/* finish using this keyboard, not used */
static int
ckb_term(keyboard_t *kbd)
{
return (ENXIO);
}
/* keyboard interrupt routine, not used */
static int
ckb_intr(keyboard_t *kbd, void *arg)
{
return (0);
}
/* lock the access to the keyboard, not used */
static int
ckb_lock(keyboard_t *kbd, int lock)
{
return (1);
}
/* clear the internal state of the keyboard */
static void
ckb_clear_state(keyboard_t *kbd)
{
struct ckb_softc *sc;
sc = kbd->kb_data;
CKB_CTX_LOCK_ASSERT();
sc->sc_flags &= ~(CKB_FLAG_COMPOSE | CKB_FLAG_POLLING);
sc->sc_state &= LOCK_MASK; /* preserve locking key state */
sc->sc_accents = 0;
}
/* save the internal state, not used */
static int
ckb_get_state(keyboard_t *kbd, void *buf, size_t len)
{
return (len == 0) ? 1 : -1;
}
/* set the internal state, not used */
static int
ckb_set_state(keyboard_t *kbd, void *buf, size_t len)
{
return (EINVAL);
}
/* check if data is waiting */
static int
ckb_check(keyboard_t *kbd)
{
struct ckb_softc *sc;
int i;
sc = kbd->kb_data;
CKB_CTX_LOCK_ASSERT();
if (!KBD_IS_ACTIVE(kbd))
return (0);
if (sc->sc_flags & CKB_FLAG_POLLING) {
return (1);
};
for (i = 0; i < sc->cols; i++)
if (sc->scan_local[i] != sc->scan[i]) {
return (1);
};
if (sc->sc_repeating)
return (1);
return (0);
}
/* check if char is waiting */
static int
ckb_check_char_locked(keyboard_t *kbd)
{
CKB_CTX_LOCK_ASSERT();
if (!KBD_IS_ACTIVE(kbd))
return (0);
return (ckb_check(kbd));
}
static int
ckb_check_char(keyboard_t *kbd)
{
int result;
CKB_LOCK();
result = ckb_check_char_locked(kbd);
CKB_UNLOCK();
return (result);
}
/* read one byte from the keyboard if it's allowed */
/* Currently unused. */
static int
ckb_read(keyboard_t *kbd, int wait)
{
CKB_CTX_LOCK_ASSERT();
if (!KBD_IS_ACTIVE(kbd))
return (-1);
printf("Implement ME: %s\n", __func__);
return (0);
}
static uint16_t
keymap_read(struct ckb_softc *sc, int col, int row)
{
KASSERT(sc->keymap != NULL, "keymap_read: no keymap");
if (col >= 0 && col < sc->cols &&
row >= 0 && row < sc->rows) {
return sc->keymap[row * sc->cols + col];
}
return (0);
}
static int
keymap_write(struct ckb_softc *sc, int col, int row, uint16_t key)
{
KASSERT(sc->keymap != NULL, "keymap_write: no keymap");
if (col >= 0 && col < sc->cols &&
row >= 0 && row < sc->rows) {
sc->keymap[row * sc->cols + col] = key;
return (0);
}
return (-1);
}
/* read char from the keyboard */
static uint32_t
ckb_read_char_locked(keyboard_t *kbd, int wait)
{
struct ckb_softc *sc;
int i,j;
uint16_t key;
int oldbit;
int newbit;
int status;
sc = kbd->kb_data;
CKB_CTX_LOCK_ASSERT();
if (!KBD_IS_ACTIVE(kbd))
return (NOKEY);
if (sc->sc_repeating) {
sc->sc_repeating = 0;
callout_reset(&sc->sc_repeat_callout, hz / 10,
ckb_repeat, sc);
return (sc->sc_repeat_key);
};
if (sc->sc_flags & CKB_FLAG_POLLING) {
for (;;) {
GPIO_PIN_GET(sc->gpio_dev, sc->gpio, &status);
if (status == 0) {
if (ec_command(EC_CMD_MKBP_STATE, sc->scan,
sc->cols,
sc->scan, sc->cols)) {
return (NOKEY);
}
break;
}
if (!wait) {
return (NOKEY);
}
DELAY(1000);
}
};
for (i = 0; i < sc->cols; i++) {
for (j = 0; j < sc->rows; j++) {
oldbit = (sc->scan_local[i] & (1 << j));
newbit = (sc->scan[i] & (1 << j));
if (oldbit == newbit)
continue;
key = keymap_read(sc, i, j);
if (key == 0) {
continue;
};
if (newbit > 0) {
/* key pressed */
sc->scan_local[i] |= (1 << j);
/* setup repeating */
sc->sc_repeat_key = key;
callout_reset(&sc->sc_repeat_callout,
hz / 2, ckb_repeat, sc);
} else {
/* key released */
sc->scan_local[i] &= ~(1 << j);
/* release flag */
key |= 0x80;
/* unsetup repeating */
sc->sc_repeat_key = -1;
callout_stop(&sc->sc_repeat_callout);
}
return (key);
}
}
return (NOKEY);
}
/* Currently wait is always false. */
static uint32_t
ckb_read_char(keyboard_t *kbd, int wait)
{
uint32_t keycode;
CKB_LOCK();
keycode = ckb_read_char_locked(kbd, wait);
CKB_UNLOCK();
return (keycode);
}
/* some useful control functions */
static int
ckb_ioctl_locked(keyboard_t *kbd, u_long cmd, caddr_t arg)
{
struct ckb_softc *sc;
int i;
sc = kbd->kb_data;
CKB_LOCK_ASSERT();
switch (cmd) {
case KDGKBMODE: /* get keyboard mode */
*(int *)arg = sc->sc_mode;
break;
case KDSKBMODE: /* set keyboard mode */
switch (*(int *)arg) {
case K_XLATE:
if (sc->sc_mode != K_XLATE) {
/* make lock key state and LED state match */
sc->sc_state &= ~LOCK_MASK;
sc->sc_state |= KBD_LED_VAL(kbd);
}
/* FALLTHROUGH */
case K_RAW:
case K_CODE:
if (sc->sc_mode != *(int *)arg) {
if ((sc->sc_flags & CKB_FLAG_POLLING) == 0)
ckb_clear_state(kbd);
sc->sc_mode = *(int *)arg;
}
break;
default:
return (EINVAL);
}
break;
case KDGETLED: /* get keyboard LED */
*(int *)arg = KBD_LED_VAL(kbd);
break;
case KDSETLED: /* set keyboard LED */
/* NOTE: lock key state in "sc_state" won't be changed */
if (*(int *)arg & ~LOCK_MASK)
return (EINVAL);
i = *(int *)arg;
/* replace CAPS LED with ALTGR LED for ALTGR keyboards */
if (sc->sc_mode == K_XLATE &&
kbd->kb_keymap->n_keys > ALTGR_OFFSET) {
if (i & ALKED)
i |= CLKED;
else
i &= ~CLKED;
}
if (KBD_HAS_DEVICE(kbd)) {
/* Configure LED */
}
KBD_LED_VAL(kbd) = *(int *)arg;
break;
case KDGKBSTATE: /* get lock key state */
*(int *)arg = sc->sc_state & LOCK_MASK;
break;
case KDSKBSTATE: /* set lock key state */
if (*(int *)arg & ~LOCK_MASK) {
return (EINVAL);
}
sc->sc_state &= ~LOCK_MASK;
sc->sc_state |= *(int *)arg;
/* set LEDs and quit */
return (ckb_ioctl(kbd, KDSETLED, arg));
case KDSETREPEAT: /* set keyboard repeat rate (new
* interface) */
if (!KBD_HAS_DEVICE(kbd)) {
return (0);
}
if (((int *)arg)[1] < 0) {
return (EINVAL);
}
if (((int *)arg)[0] < 0) {
return (EINVAL);
}
if (((int *)arg)[0] < 200) /* fastest possible value */
kbd->kb_delay1 = 200;
else
kbd->kb_delay1 = ((int *)arg)[0];
kbd->kb_delay2 = ((int *)arg)[1];
return (0);
case KDSETRAD: /* set keyboard repeat rate (old
* interface) */
return (ckb_set_typematic(kbd, *(int *)arg));
case PIO_KEYMAP: /* set keyboard translation table */
case OPIO_KEYMAP: /* set keyboard translation table
* (compat) */
case PIO_KEYMAPENT: /* set keyboard translation table
* entry */
case PIO_DEADKEYMAP: /* set accent key translation table */
sc->sc_accents = 0;
/* FALLTHROUGH */
default:
return (genkbd_commonioctl(kbd, cmd, arg));
}
return (0);
}
static int
ckb_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
{
int result;
/*
* XXX KDGKBSTATE, KDSKBSTATE and KDSETLED can be called from any
* context where printf(9) can be called, which among other things
* includes interrupt filters and threads with any kinds of locks
* already held. For this reason it would be dangerous to acquire
* the Giant here unconditionally. On the other hand we have to
* have it to handle the ioctl.
* So we make our best effort to auto-detect whether we can grab
* the Giant or not. Blame syscons(4) for this.
*/
switch (cmd) {
case KDGKBSTATE:
case KDSKBSTATE:
case KDSETLED:
if (!mtx_owned(&Giant) && !SCHEDULER_STOPPED())
return (EDEADLK); /* best I could come up with */
/* FALLTHROUGH */
default:
CKB_LOCK();
result = ckb_ioctl_locked(kbd, cmd, arg);
CKB_UNLOCK();
return (result);
}
}
/*
* Enable the access to the device; until this function is called,
* the client cannot read from the keyboard.
*/
static int
ckb_enable(keyboard_t *kbd)
{
CKB_LOCK();
KBD_ACTIVATE(kbd);
CKB_UNLOCK();
return (0);
}
/* disallow the access to the device */
static int
ckb_disable(keyboard_t *kbd)
{
CKB_LOCK();
KBD_DEACTIVATE(kbd);
CKB_UNLOCK();
return (0);
}
/* local functions */
static int
ckb_set_typematic(keyboard_t *kbd, int code)
{
static const int delays[] = {250, 500, 750, 1000};
static const int rates[] = {34, 38, 42, 46, 50, 55, 59, 63,
68, 76, 84, 92, 100, 110, 118, 126,
136, 152, 168, 184, 200, 220, 236, 252,
272, 304, 336, 368, 400, 440, 472, 504};
if (code & ~0x7f) {
return (EINVAL);
}
kbd->kb_delay1 = delays[(code >> 5) & 3];
kbd->kb_delay2 = rates[code & 0x1f];
return (0);
}
static int
ckb_poll(keyboard_t *kbd, int on)
{
struct ckb_softc *sc;
sc = kbd->kb_data;
CKB_LOCK();
if (on) {
sc->sc_flags |= CKB_FLAG_POLLING;
sc->sc_poll_thread = curthread;
} else {
sc->sc_flags &= ~CKB_FLAG_POLLING;
}
CKB_UNLOCK();
return (0);
}
/* local functions */
static int dummy_kbd_configure(int flags);
keyboard_switch_t ckbdsw = {
.probe = &ckb__probe,
.init = &ckb_init,
.term = &ckb_term,
.intr = &ckb_intr,
.test_if = &ckb_test_if,
.enable = &ckb_enable,
.disable = &ckb_disable,
.read = &ckb_read,
.check = &ckb_check,
.read_char = &ckb_read_char,
.check_char = &ckb_check_char,
.ioctl = &ckb_ioctl,
.lock = &ckb_lock,
.clear_state = &ckb_clear_state,
.get_state = &ckb_get_state,
.set_state = &ckb_set_state,
.get_fkeystr = &genkbd_get_fkeystr,
.poll = &ckb_poll,
.diag = &genkbd_diag,
};
static int
dummy_kbd_configure(int flags)
{
return (0);
}
KEYBOARD_DRIVER(ckbd, ckbdsw, dummy_kbd_configure);
/*
* Parses 'keymap' into sc->keymap.
* Requires sc->cols and sc->rows to be set.
*/
static int
parse_keymap(struct ckb_softc *sc, pcell_t *keymap, size_t len)
{
int i;
sc->keymap = malloc(sc->cols * sc->rows * sizeof(sc->keymap[0]),
M_DEVBUF, M_NOWAIT | M_ZERO);
if (sc->keymap == NULL) {
return (ENOMEM);
}
for (i = 0; i < len; i++) {
/*
* Return value is ignored, we just write whatever fits into
* specified number of rows and columns and silently ignore
* everything else.
* Keymap entries follow this format: 0xRRCCKKKK
* RR - row number, CC - column number, KKKK - key code
*/
keymap_write(sc, (keymap[i] >> 16) & 0xff,
(keymap[i] >> 24) & 0xff,
keymap[i] & 0xffff);
}
return (0);
}
/* Allocates a new array for keymap and returns it in 'keymap'. */
static int
read_keymap(phandle_t node, const char *prop, pcell_t **keymap, size_t *len)
{
if ((*len = OF_getproplen(node, prop)) <= 0) {
return (ENXIO);
}
if ((*keymap = malloc(*len, M_DEVBUF, M_NOWAIT)) == NULL) {
return (ENOMEM);
}
if (OF_getencprop(node, prop, *keymap, *len) != *len) {
return (ENXIO);
}
return (0);
}
static int
parse_dts(struct ckb_softc *sc)
{
phandle_t node;
pcell_t dts_value;
pcell_t *keymap;
int len, ret;
const char *keymap_prop = NULL;
if ((node = ofw_bus_get_node(sc->dev)) == -1)
return (ENXIO);
if ((len = OF_getproplen(node, "google,key-rows")) <= 0)
return (ENXIO);
- OF_getprop(node, "google,key-rows", &dts_value, len);
- sc->rows = fdt32_to_cpu(dts_value);
+ OF_getencprop(node, "google,key-rows", &dts_value, len);
+ sc->rows = dts_value;
if ((len = OF_getproplen(node, "google,key-columns")) <= 0)
return (ENXIO);
- OF_getprop(node, "google,key-columns", &dts_value, len);
- sc->cols = fdt32_to_cpu(dts_value);
+ OF_getencprop(node, "google,key-columns", &dts_value, len);
+ sc->cols = dts_value;
if ((len = OF_getproplen(node, "freebsd,intr-gpio")) <= 0)
return (ENXIO);
- OF_getprop(node, "freebsd,intr-gpio", &dts_value, len);
- sc->gpio = fdt32_to_cpu(dts_value);
+ OF_getencprop(node, "freebsd,intr-gpio", &dts_value, len);
+ sc->gpio = dts_value;
if (OF_hasprop(node, "freebsd,keymap")) {
keymap_prop = "freebsd,keymap";
device_printf(sc->dev, "using FreeBSD-specific keymap from FDT\n");
} else if (OF_hasprop(node, "linux,keymap")) {
keymap_prop = "linux,keymap";
device_printf(sc->dev, "using Linux keymap from FDT\n");
} else {
device_printf(sc->dev, "using built-in keymap\n");
}
if (keymap_prop != NULL) {
if ((ret = read_keymap(node, keymap_prop, &keymap, &len))) {
device_printf(sc->dev,
"failed to read keymap from FDT: %d\n", ret);
return (ret);
}
ret = parse_keymap(sc, keymap, len);
free(keymap, M_DEVBUF);
if (ret) {
return (ret);
}
} else {
if ((ret = parse_keymap(sc, default_keymap, KEYMAP_LEN))) {
return (ret);
}
}
if ((sc->rows == 0) || (sc->cols == 0) || (sc->gpio == 0))
return (ENXIO);
return (0);
}
void
ckb_ec_intr(void *arg)
{
struct ckb_softc *sc;
sc = arg;
if (sc->sc_flags & CKB_FLAG_POLLING)
return;
ec_command(EC_CMD_MKBP_STATE, sc->scan, sc->cols,
sc->scan, sc->cols);
(sc->sc_kbd.kb_callback.kc_func) (&sc->sc_kbd, KBDIO_KEYINPUT,
sc->sc_kbd.kb_callback.kc_arg);
};
static int
chrome_kb_attach(device_t dev)
{
struct ckb_softc *sc;
keyboard_t *kbd;
int error;
int rid;
int i;
sc = device_get_softc(dev);
sc->dev = dev;
sc->keymap = NULL;
if ((error = parse_dts(sc)) != 0)
return error;
sc->gpio_dev = devclass_get_device(devclass_find("gpio"), 0);
if (sc->gpio_dev == NULL) {
device_printf(sc->dev, "Can't find gpio device.\n");
return (ENXIO);
}
#if 0
device_printf(sc->dev, "Keyboard matrix [%dx%d]\n",
sc->cols, sc->rows);
#endif
pad_setup_intr(sc->gpio, ckb_ec_intr, sc);
kbd = &sc->sc_kbd;
rid = 0;
sc->scan_local = malloc(sc->cols, M_DEVBUF, M_NOWAIT);
sc->scan = malloc(sc->cols, M_DEVBUF, M_NOWAIT);
for (i = 0; i < sc->cols; i++) {
sc->scan_local[i] = 0;
sc->scan[i] = 0;
};
kbd_init_struct(kbd, KBD_DRIVER_NAME, KB_OTHER,
device_get_unit(dev), 0, 0, 0);
kbd->kb_data = (void *)sc;
sc->sc_keymap = key_map;
sc->sc_accmap = accent_map;
for (i = 0; i < CKB_NFKEY; i++) {
sc->sc_fkeymap[i] = fkey_tab[i];
}
kbd_set_maps(kbd, &sc->sc_keymap, &sc->sc_accmap,
sc->sc_fkeymap, CKB_NFKEY);
KBD_FOUND_DEVICE(kbd);
ckb_clear_state(kbd);
KBD_PROBE_DONE(kbd);
callout_init(&sc->sc_repeat_callout, 0);
KBD_INIT_DONE(kbd);
if (kbd_register(kbd) < 0) {
return (ENXIO);
};
KBD_CONFIG_DONE(kbd);
return (0);
}
static int
chrome_kb_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (ofw_bus_is_compatible(dev, "google,cros-ec-keyb") ||
ofw_bus_is_compatible(dev, "google,mkbp-keyb")) {
device_set_desc(dev, "Chrome EC Keyboard");
return (BUS_PROBE_DEFAULT);
}
return (ENXIO);
}
static int
chrome_kb_detach(device_t dev)
{
struct ckb_softc *sc;
sc = device_get_softc(dev);
if (sc->keymap != NULL) {
free(sc->keymap, M_DEVBUF);
}
return 0;
}
static device_method_t chrome_kb_methods[] = {
DEVMETHOD(device_probe, chrome_kb_probe),
DEVMETHOD(device_attach, chrome_kb_attach),
DEVMETHOD(device_detach, chrome_kb_detach),
{ 0, 0 }
};
static driver_t chrome_kb_driver = {
"chrome_kb",
chrome_kb_methods,
sizeof(struct ckb_softc),
};
static devclass_t chrome_kb_devclass;
DRIVER_MODULE(chrome_kb, simplebus, chrome_kb_driver,
chrome_kb_devclass, 0, 0);
diff --git a/sys/arm/samsung/exynos/exynos5_fimd.c b/sys/arm/samsung/exynos/exynos5_fimd.c
index d7b7330fb7f3..2a02074ec1f1 100644
--- a/sys/arm/samsung/exynos/exynos5_fimd.c
+++ b/sys/arm/samsung/exynos/exynos5_fimd.c
@@ -1,413 +1,412 @@
/*-
* Copyright (c) 2014 Ruslan Bukin
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Samsung Exynos 5 Display Controller
* Chapter 15, Exynos 5 Dual User's Manual Public Rev 1.00
*/
#include
__FBSDID("$FreeBSD$");
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
+#include
-#include
#include
#include
#include
#include
#include
#include
#include "gpio_if.h"
#include
-#include
#include
#include
#include "fb_if.h"
#define FIMDBYPASS_DISP1 (1 << 15)
#define VIDCON0 (0x0)
#define VIDCON0_ENVID (1 << 1)
#define VIDCON0_ENVID_F (1 << 0)
#define CLKVAL_F 0xb
#define CLKVAL_F_OFFSET 6
#define WINCON0 0x0020
#define WINCON1 0x0024
#define WINCON2 0x0028
#define WINCON3 0x002C
#define WINCON4 0x0030
#define ENLOCAL_F (1 << 22)
#define BPPMODE_F_RGB_16BIT_565 0x5
#define BPPMODE_F_OFFSET 2
#define ENWIN_F_ENABLE (1 << 0)
#define HALF_WORD_SWAP_EN (1 << 16)
#define SHADOWCON 0x0034
#define CHANNEL0_EN (1 << 0)
#define VIDOSD0A 0x0040
#define VIDOSD0B 0x0044
#define VIDOSD0C 0x0048
#define VIDW00ADD0B0 0x00A0
#define VIDW00ADD0B1 0x00A4
#define VIDW00ADD0B2 0x20A0
#define VIDW00ADD1B0 0x00D0
#define VIDW00ADD1B1 0x00D4
#define VIDW00ADD1B2 0x20D0
#define VIDW00ADD2 0x0100
#define VIDW01ADD2 0x0104
#define VIDW02ADD2 0x0108
#define VIDW03ADD2 0x010C
#define VIDW04ADD2 0x0110
#define VIDCON1 (0x04)
#define VIDTCON0 0x0010
#define VIDTCON1 0x0014
#define VIDTCON2 0x0018
#define VIDTCON3 0x001C
#define VIDINTCON0 0x0130
#define VIDINTCON1 0x0134
#define VSYNC_PULSE_WIDTH_VAL 0x3
#define VSYNC_PULSE_WIDTH_OFFSET 0
#define V_FRONT_PORCH_VAL 0x3
#define V_FRONT_PORCH_OFFSET 8
#define V_BACK_PORCH_VAL 0x3
#define V_BACK_PORCH_OFFSET 16
#define HSYNC_PULSE_WIDTH_VAL 0x3
#define HSYNC_PULSE_WIDTH_OFFSET 0
#define H_FRONT_PORCH_VAL 0x3
#define H_FRONT_PORCH_OFFSET 8
#define H_BACK_PORCH_VAL 0x3
#define H_BACK_PORCH_OFFSET 16
#define HOZVAL_OFFSET 0
#define LINEVAL_OFFSET 11
#define OSD_RIGHTBOTX_F_OFFSET 11
#define OSD_RIGHTBOTY_F_OFFSET 0
#define DPCLKCON 0x27c
#define DPCLKCON_EN (1 << 1)
#define DREAD4(_sc, _reg) \
bus_space_read_4(_sc->bst_disp, _sc->bsh_disp, _reg)
#define DWRITE4(_sc, _reg, _val) \
bus_space_write_4(_sc->bst_disp, _sc->bsh_disp, _reg, _val)
struct panel_info {
uint32_t width;
uint32_t height;
uint32_t h_back_porch;
uint32_t h_pulse_width;
uint32_t h_front_porch;
uint32_t v_back_porch;
uint32_t v_pulse_width;
uint32_t v_front_porch;
uint32_t clk_div;
uint32_t backlight_pin;
uint32_t fixvclk;
uint32_t ivclk;
uint32_t clkval_f;
};
struct fimd_softc {
struct resource *res[3];
bus_space_tag_t bst;
bus_space_handle_t bsh;
bus_space_tag_t bst_disp;
bus_space_handle_t bsh_disp;
bus_space_tag_t bst_sysreg;
bus_space_handle_t bsh_sysreg;
void *ih;
device_t dev;
device_t sc_fbd; /* fbd child */
struct fb_info sc_info;
struct panel_info *panel;
};
static struct resource_spec fimd_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Timer registers */
{ SYS_RES_MEMORY, 1, RF_ACTIVE }, /* FIMD */
{ SYS_RES_MEMORY, 2, RF_ACTIVE }, /* DISP */
{ -1, 0 }
};
static int
fimd_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (!ofw_bus_is_compatible(dev, "exynos,fimd"))
return (ENXIO);
device_set_desc(dev, "Samsung Exynos 5 Display Controller");
return (BUS_PROBE_DEFAULT);
}
static int
get_panel_info(struct fimd_softc *sc, struct panel_info *panel)
{
phandle_t node;
pcell_t dts_value[3];
int len;
if ((node = ofw_bus_get_node(sc->dev)) == -1)
return (ENXIO);
/* panel size */
if ((len = OF_getproplen(node, "panel-size")) <= 0)
return (ENXIO);
- OF_getprop(node, "panel-size", &dts_value, len);
- panel->width = fdt32_to_cpu(dts_value[0]);
- panel->height = fdt32_to_cpu(dts_value[1]);
+ OF_getencprop(node, "panel-size", dts_value, len);
+ panel->width = dts_value[0];
+ panel->height = dts_value[1];
/* hsync */
if ((len = OF_getproplen(node, "panel-hsync")) <= 0)
return (ENXIO);
- OF_getprop(node, "panel-hsync", &dts_value, len);
- panel->h_back_porch = fdt32_to_cpu(dts_value[0]);
- panel->h_pulse_width = fdt32_to_cpu(dts_value[1]);
- panel->h_front_porch = fdt32_to_cpu(dts_value[2]);
+ OF_getencprop(node, "panel-hsync", dts_value, len);
+ panel->h_back_porch = dts_value[0];
+ panel->h_pulse_width = dts_value[1];
+ panel->h_front_porch = dts_value[2];
/* vsync */
if ((len = OF_getproplen(node, "panel-vsync")) <= 0)
return (ENXIO);
- OF_getprop(node, "panel-vsync", &dts_value, len);
- panel->v_back_porch = fdt32_to_cpu(dts_value[0]);
- panel->v_pulse_width = fdt32_to_cpu(dts_value[1]);
- panel->v_front_porch = fdt32_to_cpu(dts_value[2]);
+ OF_getencprop(node, "panel-vsync", dts_value, len);
+ panel->v_back_porch = dts_value[0];
+ panel->v_pulse_width = dts_value[1];
+ panel->v_front_porch = dts_value[2];
/* clk divider */
if ((len = OF_getproplen(node, "panel-clk-div")) <= 0)
return (ENXIO);
- OF_getprop(node, "panel-clk-div", &dts_value, len);
- panel->clk_div = fdt32_to_cpu(dts_value[0]);
+ OF_getencprop(node, "panel-clk-div", dts_value, len);
+ panel->clk_div = dts_value[0];
/* backlight pin */
if ((len = OF_getproplen(node, "panel-backlight-pin")) <= 0)
return (ENXIO);
- OF_getprop(node, "panel-backlight-pin", &dts_value, len);
- panel->backlight_pin = fdt32_to_cpu(dts_value[0]);
+ OF_getencprop(node, "panel-backlight-pin", dts_value, len);
+ panel->backlight_pin = dts_value[0];
return (0);
}
static int
fimd_init(struct fimd_softc *sc)
{
struct panel_info *panel;
int reg;
panel = sc->panel;
/* fb_init */
reg = panel->ivclk | panel->fixvclk;
DWRITE4(sc,VIDCON1,reg);
reg = (VIDCON0_ENVID | VIDCON0_ENVID_F);
reg |= (panel->clkval_f << CLKVAL_F_OFFSET);
WRITE4(sc,VIDCON0,reg);
reg = (panel->v_pulse_width << VSYNC_PULSE_WIDTH_OFFSET);
reg |= (panel->v_front_porch << V_FRONT_PORCH_OFFSET);
reg |= (panel->v_back_porch << V_BACK_PORCH_OFFSET);
DWRITE4(sc,VIDTCON0,reg);
reg = (panel->h_pulse_width << HSYNC_PULSE_WIDTH_OFFSET);
reg |= (panel->h_front_porch << H_FRONT_PORCH_OFFSET);
reg |= (panel->h_back_porch << H_BACK_PORCH_OFFSET);
DWRITE4(sc,VIDTCON1,reg);
reg = ((panel->width - 1) << HOZVAL_OFFSET);
reg |= ((panel->height - 1) << LINEVAL_OFFSET);
DWRITE4(sc,VIDTCON2,reg);
reg = sc->sc_info.fb_pbase;
WRITE4(sc, VIDW00ADD0B0, reg);
reg += (sc->sc_info.fb_stride * (sc->sc_info.fb_height + 1));
WRITE4(sc, VIDW00ADD1B0, reg);
WRITE4(sc, VIDW00ADD2, sc->sc_info.fb_stride);
reg = ((panel->width - 1) << OSD_RIGHTBOTX_F_OFFSET);
reg |= ((panel->height - 1) << OSD_RIGHTBOTY_F_OFFSET);
WRITE4(sc,VIDOSD0B,reg);
reg = panel->width * panel->height;
WRITE4(sc,VIDOSD0C,reg);
reg = READ4(sc, SHADOWCON);
reg |= CHANNEL0_EN;
reg &= ~(1 << 5); /* disable local path for channel0 */
WRITE4(sc,SHADOWCON,reg);
reg = BPPMODE_F_RGB_16BIT_565 << BPPMODE_F_OFFSET;
reg |= ENWIN_F_ENABLE | HALF_WORD_SWAP_EN; /* Note: swap=0 when ENLOCAL==1 */
reg &= ~ENLOCAL_F; /* use DMA */
WRITE4(sc,WINCON0,reg);
/* Enable DisplayPort Clk */
WRITE4(sc, DPCLKCON, DPCLKCON_EN);
return (0);
}
static int
fimd_attach(device_t dev)
{
struct panel_info panel;
struct fimd_softc *sc;
device_t gpio_dev;
int reg;
sc = device_get_softc(dev);
sc->dev = dev;
if (bus_alloc_resources(dev, fimd_spec, sc->res)) {
device_printf(dev, "could not allocate resources\n");
return (ENXIO);
}
/* Memory interface */
sc->bst = rman_get_bustag(sc->res[0]);
sc->bsh = rman_get_bushandle(sc->res[0]);
sc->bst_disp = rman_get_bustag(sc->res[1]);
sc->bsh_disp = rman_get_bushandle(sc->res[1]);
sc->bst_sysreg = rman_get_bustag(sc->res[2]);
sc->bsh_sysreg = rman_get_bushandle(sc->res[2]);
if (get_panel_info(sc, &panel)) {
device_printf(dev, "Can't get panel info\n");
return (ENXIO);
}
panel.fixvclk = 0;
panel.ivclk = 0;
panel.clkval_f = 2;
sc->panel = &panel;
/* Get the GPIO device, we need this to give power to USB */
gpio_dev = devclass_get_device(devclass_find("gpio"), 0);
if (gpio_dev == NULL) {
/* TODO */
}
reg = bus_space_read_4(sc->bst_sysreg, sc->bsh_sysreg, 0x214);
reg |= FIMDBYPASS_DISP1;
bus_space_write_4(sc->bst_sysreg, sc->bsh_sysreg, 0x214, reg);
sc->sc_info.fb_width = panel.width;
sc->sc_info.fb_height = panel.height;
sc->sc_info.fb_stride = sc->sc_info.fb_width * 2;
sc->sc_info.fb_bpp = sc->sc_info.fb_depth = 16;
sc->sc_info.fb_size = sc->sc_info.fb_height * sc->sc_info.fb_stride;
sc->sc_info.fb_vbase = (intptr_t)kmem_alloc_contig(kernel_arena,
sc->sc_info.fb_size, M_ZERO, 0, ~0, PAGE_SIZE, 0, VM_MEMATTR_UNCACHEABLE);
sc->sc_info.fb_pbase = (intptr_t)vtophys(sc->sc_info.fb_vbase);
#if 0
printf("%dx%d [%d]\n", sc->sc_info.fb_width, sc->sc_info.fb_height,
sc->sc_info.fb_stride);
printf("pbase == 0x%08x\n", sc->sc_info.fb_pbase);
#endif
memset((int8_t *)sc->sc_info.fb_vbase, 0x0, sc->sc_info.fb_size);
fimd_init(sc);
sc->sc_info.fb_name = device_get_nameunit(dev);
/* Ask newbus to attach framebuffer device to me. */
sc->sc_fbd = device_add_child(dev, "fbd", device_get_unit(dev));
if (sc->sc_fbd == NULL)
device_printf(dev, "Can't attach fbd device\n");
if (device_probe_and_attach(sc->sc_fbd) != 0) {
device_printf(sc->dev, "Failed to attach fbd device\n");
}
return (0);
}
static struct fb_info *
fimd_fb_getinfo(device_t dev)
{
struct fimd_softc *sc = device_get_softc(dev);
return (&sc->sc_info);
}
static device_method_t fimd_methods[] = {
DEVMETHOD(device_probe, fimd_probe),
DEVMETHOD(device_attach, fimd_attach),
/* Framebuffer service methods */
DEVMETHOD(fb_getinfo, fimd_fb_getinfo),
{ 0, 0 }
};
static driver_t fimd_driver = {
"fb",
fimd_methods,
sizeof(struct fimd_softc),
};
static devclass_t fimd_devclass;
DRIVER_MODULE(fb, simplebus, fimd_driver, fimd_devclass, 0, 0);
diff --git a/sys/arm/samsung/exynos/exynos5_usb_phy.c b/sys/arm/samsung/exynos/exynos5_usb_phy.c
index 649cb34c5ec9..2756efbc337c 100644
--- a/sys/arm/samsung/exynos/exynos5_usb_phy.c
+++ b/sys/arm/samsung/exynos/exynos5_usb_phy.c
@@ -1,273 +1,271 @@
/*-
* Copyright (c) 2014 Ruslan Bukin
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* DWC3 USB 3.0 DRD (dual role device) PHY
*/
#include
__FBSDID("$FreeBSD$");
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
-#include
#include
#include
#include
#include
-#include
#include
#include
#include
#include
#include "gpio_if.h"
#define USB_DRD_LINKSYSTEM 0x04
#define LINKSYSTEM_FLADJ_MASK (0x3f << 1)
#define LINKSYSTEM_FLADJ(x) ((x) << 1)
#define LINKSYSTEM_XHCI_VERSION_CTRL (1 << 27)
#define USB_DRD_PHYUTMI 0x08
#define PHYUTMI_OTGDISABLE (1 << 6)
#define PHYUTMI_FORCESUSPEND (1 << 1)
#define PHYUTMI_FORCESLEEP (1 << 0)
#define USB_DRD_PHYPIPE 0x0c
#define USB_DRD_PHYCLKRST 0x10
#define PHYCLKRST_PORTRESET (1 << 1)
#define PHYCLKRST_COMMONONN (1 << 0)
#define PHYCLKRST_EN_UTMISUSPEND (1 << 31)
#define PHYCLKRST_SSC_REFCLKSEL_MASK (0xff << 23)
#define PHYCLKRST_SSC_REFCLKSEL(x) ((x) << 23)
#define PHYCLKRST_SSC_RANGE_MASK (0x03 << 21)
#define PHYCLKRST_SSC_RANGE(x) ((x) << 21)
#define PHYCLKRST_SSC_EN (1 << 20)
#define PHYCLKRST_REF_SSP_EN (1 << 19)
#define PHYCLKRST_REF_CLKDIV2 (1 << 18)
#define PHYCLKRST_MPLL_MLTPR_MASK (0x7f << 11)
#define PHYCLKRST_MPLL_MLTPR_100MHZ (0x19 << 11)
#define PHYCLKRST_MPLL_MLTPR_50M (0x32 << 11)
#define PHYCLKRST_MPLL_MLTPR_24MHZ (0x68 << 11)
#define PHYCLKRST_MPLL_MLTPR_20MHZ (0x7d << 11)
#define PHYCLKRST_MPLL_MLTPR_19200KHZ (0x02 << 11)
#define PHYCLKRST_FSEL_UTMI_MASK (0x7 << 5)
#define PHYCLKRST_FSEL_PIPE_MASK (0x7 << 8)
#define PHYCLKRST_FSEL(x) ((x) << 5)
#define PHYCLKRST_FSEL_9MHZ6 0x0
#define PHYCLKRST_FSEL_10MHZ 0x1
#define PHYCLKRST_FSEL_12MHZ 0x2
#define PHYCLKRST_FSEL_19MHZ2 0x3
#define PHYCLKRST_FSEL_20MHZ 0x4
#define PHYCLKRST_FSEL_24MHZ 0x5
#define PHYCLKRST_FSEL_50MHZ 0x7
#define PHYCLKRST_RETENABLEN (1 << 4)
#define PHYCLKRST_REFCLKSEL_MASK (0x03 << 2)
#define PHYCLKRST_REFCLKSEL_PAD_REFCLK (0x2 << 2)
#define PHYCLKRST_REFCLKSEL_EXT_REFCLK (0x3 << 2)
#define USB_DRD_PHYREG0 0x14
#define USB_DRD_PHYREG1 0x18
#define USB_DRD_PHYPARAM0 0x1c
#define PHYPARAM0_REF_USE_PAD (1 << 31)
#define PHYPARAM0_REF_LOSLEVEL_MASK (0x1f << 26)
#define PHYPARAM0_REF_LOSLEVEL (0x9 << 26)
#define USB_DRD_PHYPARAM1 0x20
#define PHYPARAM1_PCS_TXDEEMPH_MASK (0x1f << 0)
#define PHYPARAM1_PCS_TXDEEMPH (0x1c)
#define USB_DRD_PHYTERM 0x24
#define USB_DRD_PHYTEST 0x28
#define PHYTEST_POWERDOWN_SSP (1 << 3)
#define PHYTEST_POWERDOWN_HSP (1 << 2)
#define USB_DRD_PHYADP 0x2c
#define USB_DRD_PHYUTMICLKSEL 0x30
#define PHYUTMICLKSEL_UTMI_CLKSEL (1 << 2)
#define USB_DRD_PHYRESUME 0x34
#define USB_DRD_LINKPORT 0x44
struct usb_phy_softc {
struct resource *res[1];
bus_space_tag_t bst;
bus_space_handle_t bsh;
device_t dev;
};
static struct resource_spec usb_phy_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ -1, 0 }
};
static int
usb_phy_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (!ofw_bus_is_compatible(dev, "samsung,exynos5420-usbdrd-phy"))
return (ENXIO);
device_set_desc(dev, "Samsung Exynos 5 USB PHY");
return (BUS_PROBE_DEFAULT);
}
static int
vbus_on(struct usb_phy_softc *sc)
{
pcell_t dts_value[3];
device_t gpio_dev;
phandle_t node;
pcell_t pin;
int len;
if ((node = ofw_bus_get_node(sc->dev)) == -1)
return (-1);
/* Power pin */
if ((len = OF_getproplen(node, "vbus-supply")) <= 0)
return (-1);
- OF_getprop(node, "vbus-supply", &dts_value, len);
- pin = fdt32_to_cpu(dts_value[0]);
+ OF_getencprop(node, "vbus-supply", dts_value, len);
+ pin = dts_value[0];
gpio_dev = devclass_get_device(devclass_find("gpio"), 0);
if (gpio_dev == NULL) {
device_printf(sc->dev, "cant find gpio_dev\n");
return (1);
}
GPIO_PIN_SETFLAGS(gpio_dev, pin, GPIO_PIN_OUTPUT);
GPIO_PIN_SET(gpio_dev, pin, GPIO_PIN_HIGH);
return (0);
}
static int
usb3_phy_init(struct usb_phy_softc *sc)
{
int reg;
/* Reset USB 3.0 PHY */
WRITE4(sc, USB_DRD_PHYREG0, 0);
reg = READ4(sc, USB_DRD_PHYPARAM0);
/* PHY CLK src */
reg &= ~(PHYPARAM0_REF_USE_PAD);
reg &= ~(PHYPARAM0_REF_LOSLEVEL_MASK);
reg |= (PHYPARAM0_REF_LOSLEVEL);
WRITE4(sc, USB_DRD_PHYPARAM0, reg);
WRITE4(sc, USB_DRD_PHYRESUME, 0);
reg = (LINKSYSTEM_XHCI_VERSION_CTRL |
LINKSYSTEM_FLADJ(0x20));
WRITE4(sc, USB_DRD_LINKSYSTEM, reg);
reg = READ4(sc, USB_DRD_PHYPARAM1);
reg &= ~(PHYPARAM1_PCS_TXDEEMPH_MASK);
reg |= (PHYPARAM1_PCS_TXDEEMPH);
WRITE4(sc, USB_DRD_PHYPARAM1, reg);
reg = READ4(sc, USB_DRD_PHYUTMICLKSEL);
reg |= (PHYUTMICLKSEL_UTMI_CLKSEL);
WRITE4(sc, USB_DRD_PHYUTMICLKSEL, reg);
reg = READ4(sc, USB_DRD_PHYTEST);
reg &= ~(PHYTEST_POWERDOWN_HSP);
reg &= ~(PHYTEST_POWERDOWN_SSP);
WRITE4(sc, USB_DRD_PHYTEST, reg);
WRITE4(sc, USB_DRD_PHYUTMI, PHYUTMI_OTGDISABLE);
/* Clock */
reg = (PHYCLKRST_REFCLKSEL_EXT_REFCLK);
reg |= (PHYCLKRST_FSEL(PHYCLKRST_FSEL_24MHZ));
reg |= (PHYCLKRST_MPLL_MLTPR_24MHZ);
reg |= (PHYCLKRST_SSC_REFCLKSEL(0x88));
reg |= (PHYCLKRST_RETENABLEN |
PHYCLKRST_REF_SSP_EN | /* Super speed */
PHYCLKRST_SSC_EN | /* Spread spectrum */
PHYCLKRST_COMMONONN |
PHYCLKRST_PORTRESET);
WRITE4(sc, USB_DRD_PHYCLKRST, reg);
DELAY(50000);
reg &= ~PHYCLKRST_PORTRESET;
WRITE4(sc, USB_DRD_PHYCLKRST, reg);
return (0);
}
static int
usb_phy_attach(device_t dev)
{
struct usb_phy_softc *sc;
sc = device_get_softc(dev);
sc->dev = dev;
if (bus_alloc_resources(dev, usb_phy_spec, sc->res)) {
device_printf(dev, "could not allocate resources\n");
return (ENXIO);
}
/* Memory interface */
sc->bst = rman_get_bustag(sc->res[0]);
sc->bsh = rman_get_bushandle(sc->res[0]);
vbus_on(sc);
usbdrd_phy_power_on();
DELAY(100);
usb3_phy_init(sc);
return (0);
}
static device_method_t usb_phy_methods[] = {
DEVMETHOD(device_probe, usb_phy_probe),
DEVMETHOD(device_attach, usb_phy_attach),
{ 0, 0 }
};
static driver_t usb_phy_driver = {
"usb_phy",
usb_phy_methods,
sizeof(struct usb_phy_softc),
};
static devclass_t usb_phy_devclass;
DRIVER_MODULE(usb_phy, simplebus, usb_phy_driver, usb_phy_devclass, 0, 0);