summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorkettenis <kettenis@openbsd.org>2017-05-13 12:25:55 +0000
committerkettenis <kettenis@openbsd.org>2017-05-13 12:25:55 +0000
commitedfa3317520f93cb4db8ff3b264a0f446382d0d6 (patch)
tree587fc758fe4ac7c6310e13e24ee9563affd691a2 /sys
parentScroll the right number of lines off the region when clearing. (diff)
downloadwireguard-openbsd-edfa3317520f93cb4db8ff3b264a0f446382d0d6.tar.xz
wireguard-openbsd-edfa3317520f93cb4db8ff3b264a0f446382d0d6.zip
Handle drive strength.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/fdt/rkpinctrl.c80
1 files changed, 67 insertions, 13 deletions
diff --git a/sys/dev/fdt/rkpinctrl.c b/sys/dev/fdt/rkpinctrl.c
index 4f9b8ee70d4..6302416b884 100644
--- a/sys/dev/fdt/rkpinctrl.c
+++ b/sys/dev/fdt/rkpinctrl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rkpinctrl.c,v 1.2 2017/05/06 18:25:43 kettenis Exp $ */
+/* $OpenBSD: rkpinctrl.c,v 1.3 2017/05/13 12:25:55 kettenis Exp $ */
/*
* Copyright (c) 2017 Mark Kettenis <kettenis@openbsd.org>
*
@@ -118,19 +118,56 @@ rk3399_pull(uint32_t bank, uint32_t idx, uint32_t phandle)
return -1;
}
+/* Magic because the drive strength configurations vary wildly. */
+
+int rk3399_strength_levels[][8] = {
+ { 2, 4, 8, 12 }, /* default */
+ { 3, 6, 9, 12 }, /* 1.8V or 3.0V */
+ { 5, 10, 15, 20 }, /* 1.8V only */
+ { 4, 6, 8, 10, 12, 14, 16, 18 }, /* 1.8V or 3.0V auto */
+ { 4, 7, 10, 13, 16, 19, 22, 26 }, /* 3.3V */
+};
+
+int rk3399_strength_types[][4] = {
+ { 2, 2, 0, 0 },
+ { 1, 1, 1, 1 },
+ { 1, 1, 2, 2 },
+ { 4, 4, 4, 1 },
+ { 1, 3, 1, 1 },
+};
+
+int rk3399_strength_regs[][4] = {
+ { 0x0080, 0x0088, 0x0090, 0x0098 },
+ { 0x00a0, 0x00a8, 0x00b0, 0x00b8 },
+ { 0x0100, 0x0104, 0x0108, 0x010c },
+ { 0x0110, 0x0118, 0x0120, 0x0128 },
+ { 0x012c, 0x0130, 0x0138, 0x013c },
+};
+
int
-rk3399_strength(uint32_t phandle)
+rk3399_strength(uint32_t bank, uint32_t idx, uint32_t phandle)
{
+ int strength, type, level;
+ int *levels;
int node;
node = OF_getnodebyphandle(phandle);
if (node == 0)
return -1;
- /* XXX decode levels. */
- return OF_getpropint(node, "drive-strength", -1);
-}
+ strength = OF_getpropint(node, "drive-strength", -1);
+ if (strength == -1)
+ return -1;
+ /* Convert drive strength to level. */
+ type = rk3399_strength_types[bank][idx / 8];
+ levels = rk3399_strength_levels[type];
+ for (level = 7; level >= 0; level--) {
+ if (strength >= levels[level] && levels[level] > 0)
+ break;
+ }
+ return level;
+}
int
rk3399_pinctrl(uint32_t phandle, void *cookie)
@@ -155,32 +192,30 @@ rk3399_pinctrl(uint32_t phandle, void *cookie)
struct regmap *rm;
bus_size_t base, off;
uint32_t bank, idx, mux;
- int pull, strength;
+ int pull, strength, type, shift;
uint32_t mask, bits;
+ int s;
bank = pins[i];
idx = pins[i + 1];
mux = pins[i + 2];
pull = rk3399_pull(bank, idx, pins[i + 3]);
- strength = rk3399_strength(pins[i + 3]);
+ strength = rk3399_strength(bank, idx, pins[i + 3]);
if (bank > 5 || idx > 32 || mux > 3)
continue;
- /* XXX leave alone for now */
- if (strength >= 0)
- continue;
-
/* Bank 0 and 1 live in the PMU. */
if (bank < 2) {
rm = sc->sc_pmu;
base = RK3399_PMUGRF_GPIO0A_IOMUX;
} else {
rm = sc->sc_grf;
- base = RK3399_GRF_GPIO2A_IOMUX;
- bank -= 2;
+ base = RK3399_GRF_GPIO2A_IOMUX - 0x20;
}
+ s = splhigh();
+
/* IOMUX control */
off = bank * 0x10 + (idx / 8) * 0x04;
mask = (0x3 << ((idx % 8) * 2));
@@ -194,6 +229,25 @@ rk3399_pinctrl(uint32_t phandle, void *cookie)
bits = (pull << ((idx % 8) * 2));
regmap_write_4(rm, base + off, mask << 16 | bits);
}
+
+ /* GPIO drive strength control */
+ if (strength >= 0) {
+ off = rk3399_strength_regs[bank][idx / 8];
+ type = rk3399_strength_types[bank][idx / 8];
+ shift = (type > 2) ? 3 : 2;
+ mask = (((1 << shift) - 1) << ((idx % 8) * shift));
+ bits = (strength << ((idx % 8) * shift));
+ if (mask & 0x0000ffff) {
+ regmap_write_4(rm, base + off,
+ mask << 16 | (bits & 0x0000ffff));
+ }
+ if (mask & 0xffff0000) {
+ regmap_write_4(rm, base + off + 0x04,
+ (mask & 0xffff0000) | bits >> 16);
+ }
+ }
+
+ splx(s);
}
free(pins, M_TEMP, len);