aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2019-03-25 15:58:49 +0000
committerPeter Maydell <peter.maydell@linaro.org>2019-03-25 15:58:49 +0000
commit50ccc488b0d4c3b8e2790c18bcd7329fc609a1c6 (patch)
tree843306c6ffcdec524acfcdcad97a94a4d83367e8 /hw
parentadb3321bfdeabeeb32b5ec545043a3f5f9fd8a7e (diff)
parentf2b2f53f6429b5abd7cd86bd65747f5f13e195eb (diff)
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20190325' into staging
target-arm queue: * Fix non-parallel expansion of CASP * nrf51_gpio: reflect pull-up/pull-down to IRQs * Fix crash if guest tries to enable non-existent PMU counters * Add PMUv2 to the Cortex-A15 and Cortex-A7 * Make pmccntr_op_start/finish static # gpg: Signature made Mon 25 Mar 2019 14:19:47 GMT # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20190325: target/arm: make pmccntr_op_start/finish static target/arm: cortex-a7 and cortex-a15 have pmus target/arm: fix crash on pmu register access target/arm: add PCI_TESTDEV back to default config nrf51_gpio: reflect pull-up/pull-down to IRQs target/arm: Fix non-parallel expansion of CASP Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/gpio/nrf51_gpio.c65
1 files changed, 40 insertions, 25 deletions
diff --git a/hw/gpio/nrf51_gpio.c b/hw/gpio/nrf51_gpio.c
index 86e047d649..87a2f2a0dc 100644
--- a/hw/gpio/nrf51_gpio.c
+++ b/hw/gpio/nrf51_gpio.c
@@ -43,6 +43,17 @@ static bool is_connected(uint32_t config, uint32_t level)
return state;
}
+static int pull_value(uint32_t config)
+{
+ int pull = extract32(config, 2, 2);
+ if (pull == NRF51_GPIO_PULLDOWN) {
+ return 0;
+ } else if (pull == NRF51_GPIO_PULLUP) {
+ return 1;
+ }
+ return -1;
+}
+
static void update_output_irq(NRF51GPIOState *s, size_t i,
bool connected, bool level)
{
@@ -61,43 +72,47 @@ static void update_output_irq(NRF51GPIOState *s, size_t i,
static void update_state(NRF51GPIOState *s)
{
- uint32_t pull;
+ int pull;
size_t i;
- bool connected_out, dir, connected_in, out, input;
+ bool connected_out, dir, connected_in, out, in, input;
for (i = 0; i < NRF51_GPIO_PINS; i++) {
- pull = extract32(s->cnf[i], 2, 2);
+ pull = pull_value(s->cnf[i]);
dir = extract32(s->cnf[i], 0, 1);
connected_in = extract32(s->in_mask, i, 1);
out = extract32(s->out, i, 1);
+ in = extract32(s->in, i, 1);
input = !extract32(s->cnf[i], 1, 1);
connected_out = is_connected(s->cnf[i], out) && dir;
- update_output_irq(s, i, connected_out, out);
-
- /* Pin both driven externally and internally */
- if (connected_out && connected_in) {
- qemu_log_mask(LOG_GUEST_ERROR, "GPIO pin %zu short circuited\n", i);
- }
-
- /*
- * Input buffer disconnected from internal/external drives, so
- * pull-up/pull-down becomes relevant
- */
- if (!input || (input && !connected_in && !connected_out)) {
- if (pull == NRF51_GPIO_PULLDOWN) {
- s->in = deposit32(s->in, i, 1, 0);
- } else if (pull == NRF51_GPIO_PULLUP) {
- s->in = deposit32(s->in, i, 1, 1);
+ if (!input) {
+ if (pull >= 0) {
+ /* Input buffer disconnected from external drives */
+ s->in = deposit32(s->in, i, 1, pull);
+ }
+ } else {
+ if (connected_out && connected_in && out != in) {
+ /* Pin both driven externally and internally */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "GPIO pin %zu short circuited\n", i);
+ }
+ if (!connected_in) {
+ /*
+ * Floating input: the output stimulates IN if connected,
+ * otherwise pull-up/pull-down resistors put a value on both
+ * IN and OUT.
+ */
+ if (pull >= 0 && !connected_out) {
+ connected_out = true;
+ out = pull;
+ }
+ if (connected_out) {
+ s->in = deposit32(s->in, i, 1, out);
+ }
}
}
-
- /* Self stimulation through internal output driver */
- if (connected_out && !connected_in && input) {
- s->in = deposit32(s->in, i, 1, out);
- }
+ update_output_irq(s, i, connected_out, out);
}
-
}
/*