diff options
author | 2017-05-13 12:25:55 +0000 | |
---|---|---|
committer | 2017-05-13 12:25:55 +0000 | |
commit | edfa3317520f93cb4db8ff3b264a0f446382d0d6 (patch) | |
tree | 587fc758fe4ac7c6310e13e24ee9563affd691a2 /sys | |
parent | Scroll the right number of lines off the region when clearing. (diff) | |
download | wireguard-openbsd-edfa3317520f93cb4db8ff3b264a0f446382d0d6.tar.xz wireguard-openbsd-edfa3317520f93cb4db8ff3b264a0f446382d0d6.zip |
Handle drive strength.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/fdt/rkpinctrl.c | 80 |
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); |