summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoy Cho <joy.cho@hardkernel.com>2018-12-04 17:08:44 +0900
committerDongjin Kim <tobetter@gmail.com>2020-02-13 17:13:40 +0900
commit17799f47c2542f6baccfd5fd88c4d12afef542be (patch)
treed5538382216303c4e098076844ed35ed0f9aaec2
parentc699a267dbc23e6a02459284d633c62d41bface4 (diff)
downloadu-boot-odroid-c1-17799f47c2542f6baccfd5fd88c4d12afef542be.tar.gz
ODROID-C4: scp_task: add gpio wake-up function
Change-Id: Idaa9f5738b02d7815762aba6a1513fefcc4deda6
-rw-r--r--arch/arm/cpu/armv8/g12a/firmware/scp_task/gpio_key.c259
-rw-r--r--arch/arm/cpu/armv8/g12a/firmware/scp_task/gpio_key.h29
-rw-r--r--arch/arm/cpu/armv8/g12a/firmware/scp_task/suspend.c11
-rw-r--r--arch/arm/cpu/armv8/g12a/firmware/scp_task/suspend.h2
-rw-r--r--board/hardkernel/odroidc4/firmware/scp_task/pwr_ctrl.c17
5 files changed, 318 insertions, 0 deletions
diff --git a/arch/arm/cpu/armv8/g12a/firmware/scp_task/gpio_key.c b/arch/arm/cpu/armv8/g12a/firmware/scp_task/gpio_key.c
new file mode 100644
index 0000000000..833ba5fdc6
--- /dev/null
+++ b/arch/arm/cpu/armv8/g12a/firmware/scp_task/gpio_key.c
@@ -0,0 +1,259 @@
+/*
+ * arch/arm/cpu/armv8/g12a/firmware/scp_task/gpio_key.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <gpio.h>
+#include <aml_gpio.h>
+
+#define PK(reg, bit) ((reg << 8) | bit)
+#define PK_REG(value) (value >> 8)
+
+#define EE_OFFSET 12
+#define GPIOAO(x) (x)
+#define GPIOEE(x) (EE_OFFSET + x)
+
+#define KERNEL_GPIO_OFFSET 399
+
+static unsigned int g_bankindex;
+static unsigned int g_offset;
+static unsigned int g_active;
+
+unsigned int gpio_wakeup_keyno;
+
+/*
+ * Support only default pull-up ports
+ * on this version
+ */
+static struct gpio_array {
+ unsigned int pin;
+ unsigned int function;
+} gpio_to_pin[] = {
+ {
+ .pin = (GPIOA_14 + EE_OFFSET),
+ .function = PK(0xe, 14),
+ },
+ {
+ .pin = (GPIOX_0 + EE_OFFSET),
+ .function = PK(3, 0),
+ },
+ {
+ .pin = (GPIOX_1 + EE_OFFSET),
+ .function = PK(3, 1),
+ },
+ {
+ .pin = (GPIOX_2 + EE_OFFSET),
+ .function = PK(3, 2),
+ },
+ {
+ .pin = (GPIOX_3 + EE_OFFSET),
+ .function = PK(3, 3),
+ },
+ {
+ .pin = (GPIOX_4 + EE_OFFSET),
+ .function = PK(3, 4),
+ },
+ {
+ .pin = (GPIOX_5 + EE_OFFSET),
+ .function = PK(3, 5),
+ },
+ {
+ .pin = (GPIOX_7 + EE_OFFSET),
+ .function = PK(3, 7),
+ },
+ {
+ .pin = (GPIOX_8 + EE_OFFSET),
+ .function = PK(4, 8),
+ },
+ {
+ .pin = (GPIOX_9 + EE_OFFSET),
+ .function = PK(4, 9),
+ },
+ {
+ .pin = (GPIOX_10 + EE_OFFSET),
+ .function = PK(4, 10),
+ },
+ {
+ .pin = (GPIOX_11 + EE_OFFSET),
+ .function = PK(4, 11),
+ },
+ {
+ .pin = (GPIOX_12 + EE_OFFSET),
+ .function = PK(4, 12),
+ },
+ {
+ .pin = (GPIOX_13 + EE_OFFSET),
+ .function = PK(4, 13),
+ },
+ {
+ .pin = (GPIOX_14 + EE_OFFSET),
+ .function = PK(4, 14),
+ },
+ {
+ .pin = (GPIOX_15 + EE_OFFSET),
+ .function = PK(4, 15),
+ },
+ {
+ .pin = (GPIOX_16 + EE_OFFSET),
+ .function = PK(5, 16),
+ },
+ {
+ .pin = (GPIOX_18 + EE_OFFSET),
+ .function = PK(5, 18),
+ },
+};
+
+#define BANK(n, f, l, per, peb, pr, pb, dr, db, or, ob, ir, ib) \
+{ \
+ .name = n, \
+ .first = f, \
+ .last = l, \
+ .regs = { \
+ [REG_PULLEN] = { (0xff634520 + (per<<2)), peb }, \
+ [REG_PULL] = { (0xff6344e8 + (pr<<2)), pb }, \
+ [REG_DIR] = { (0xff634440 + (dr<<2)), db }, \
+ [REG_OUT] = { (0xff634440 + (or<<2)), ob }, \
+ [REG_IN] = { (0xff634440 + (ir<<2)), ib }, \
+ }, \
+ }
+
+static struct meson_bank mesong12b_banks[] = {
+ /* name first last
+ * pullen pull dir out in */
+ BANK("GPIOA_", GPIOEE(GPIOA_0), GPIOEE(GPIOA_15),
+ 5, 0, 5, 0, 16, 0, 17, 0, 18, 0),
+ BANK("GPIOX_", GPIOEE(GPIOX_0), GPIOEE(GPIOX_19),
+ 2, 0, 2, 0, 6, 0, 7, 0, 8, 0),
+};
+
+/* GPIOEE pin mux registers */
+static unsigned long domain = 0xff6346c0;
+
+/* active level - 0 : active low, 1 : active high */
+static unsigned long active_tbl[] = {
+ [0] = 0x00003FFF, /* GPIOA */
+ [1] = 0x000A0040, /* GPIOX */
+};
+
+int clear_pinmux(unsigned int pin)
+{
+ unsigned int i;
+ unsigned int reg = 0;
+ unsigned int bit = 0;
+
+ for (i = 0; i < ARRAY_SIZE(gpio_to_pin); i++) {
+ if (gpio_to_pin[i].pin == pin) {
+ reg = (PK_REG(gpio_to_pin[i].function) & 0xf);
+ g_offset = (gpio_to_pin[i].function & 0xff);
+ bit = ((g_offset % 8) * 4);
+ aml_update_bits((domain + (reg << 2)), (0xf << bit), 0);
+ break;
+ }
+ }
+
+ if (i >= ARRAY_SIZE(gpio_to_pin))
+ return 0;
+ else
+ return 1;
+}
+
+int init_gpio_key(void)
+{
+ unsigned int key_index;
+ unsigned int reg, bit;
+ struct meson_bank bank;
+
+ key_index = gpio_wakeup_keyno - KERNEL_GPIO_OFFSET;
+ if ((key_index >= (GPIOA_0 + EE_OFFSET))
+ && (key_index < (GPIOA_15 + EE_OFFSET))) {
+ g_bankindex = 0;
+ } else if ((key_index >= GPIOX_0 + EE_OFFSET)
+ && (key_index < (GPIOX_19 + EE_OFFSET))) {
+ g_bankindex = 1;
+ } else {
+ uart_puts("WAKEUP GPIO FAIL - invalid key \n");
+ uart_put_hex(key_index, 32);
+ uart_puts("\n");
+ return 0;
+ }
+
+ /* clear_pinmux */
+ if (!clear_pinmux(key_index))
+ return 0;
+
+ /* active level */
+ g_active = ((active_tbl[g_bankindex] >> g_offset) & 0x1);
+
+ /* set as input port */
+ bank = mesong12b_banks[g_bankindex];
+ reg = bank.regs[REG_DIR].reg;
+ bit = bank.regs[REG_DIR].bit + g_offset;
+ aml_update_bits(reg, BIT(bit), BIT(bit));
+
+ return 1;
+}
+
+int key_chattering(void)
+{
+ unsigned int count = 0;
+ unsigned int key_pressed = 1;
+ unsigned int reg, bit;
+ unsigned int active_value;
+ struct meson_bank bank = mesong12b_banks[g_bankindex];
+
+ reg = bank.regs[REG_IN].reg;
+ bit = bank.regs[REG_IN].bit + g_offset;
+
+ if (g_active)
+ active_value = (1 << bit);
+ else
+ active_value = 0;
+
+ while (key_pressed) {
+ _udelay(1000);
+
+ if ((readl(reg) & (1 << bit)) == active_value)
+ count++;
+ else
+ key_pressed = 0;
+
+ if (count == 300)
+ return 1;
+ }
+
+ return 0;
+}
+
+int gpio_detect_key(void)
+{
+ unsigned int reg, bit;
+ unsigned int active_value;
+ struct meson_bank bank = mesong12b_banks[g_bankindex];
+
+ reg = bank.regs[REG_IN].reg;
+ bit = bank.regs[REG_IN].bit + g_offset;
+
+ if (g_active)
+ active_value = (1 << bit);
+ else
+ active_value = 0;
+
+ if ((readl(reg) & (1 << bit)) == active_value)
+ if (key_chattering())
+ return 1;
+
+ return 0;
+}
diff --git a/arch/arm/cpu/armv8/g12a/firmware/scp_task/gpio_key.h b/arch/arm/cpu/armv8/g12a/firmware/scp_task/gpio_key.h
new file mode 100644
index 0000000000..8adaae81a6
--- /dev/null
+++ b/arch/arm/cpu/armv8/g12a/firmware/scp_task/gpio_key.h
@@ -0,0 +1,29 @@
+/*
+ * arch/arm/cpu/armv8/g12a/firmware/scp_task/gpio_key.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __ARCH_G12B_GPIO_KEY_H__
+#define __ARCH_G12B_GPIO_KEY_H__
+
+#ifdef CONFIG_GPIO_WAKEUP
+int gpio_detect_key(void);
+int init_gpio_key(void);
+
+unsigned int gpio_wakeup_keyno;
+#endif
+
+#endif /* __ARCH_G12B_GPIO_KEY_H__ */
diff --git a/arch/arm/cpu/armv8/g12a/firmware/scp_task/suspend.c b/arch/arm/cpu/armv8/g12a/firmware/scp_task/suspend.c
index 7274ada541..7f89610722 100644
--- a/arch/arm/cpu/armv8/g12a/firmware/scp_task/suspend.c
+++ b/arch/arm/cpu/armv8/g12a/firmware/scp_task/suspend.c
@@ -29,6 +29,7 @@ unsigned int time;
#include <scp_adc.c>
#include <pwr_ctrl.c>
#include <hdmi_cec_arc.c>
+#include <gpio_key.c>
static struct pwr_op pwr_op_d;
static struct pwr_op *p_pwr_op;
@@ -62,6 +63,16 @@ void enter_suspend(unsigned int suspend_from)
uart_put_hex(hdmi_cec_func_config, 16);
uart_puts("\n");
#endif
+
+ #ifdef CONFIG_GPIO_WAKEUP
+ gpio_wakeup_keyno = ((readl(P_AO_DEBUG_REG0) & 0xfff0000) >> 16);
+ wait_uart_empty();
+ uart_puts("WAKEUP GPIO cfg:0x");
+ uart_put_hex(gpio_wakeup_keyno, 32);
+ uart_puts("\n");
+ wait_uart_empty();
+ #endif
+
if (p_pwr_op->power_off_at_24M)
p_pwr_op->power_off_at_24M(suspend_from);
diff --git a/arch/arm/cpu/armv8/g12a/firmware/scp_task/suspend.h b/arch/arm/cpu/armv8/g12a/firmware/scp_task/suspend.h
index cc1fc5f8e9..a3c270ad92 100644
--- a/arch/arm/cpu/armv8/g12a/firmware/scp_task/suspend.h
+++ b/arch/arm/cpu/armv8/g12a/firmware/scp_task/suspend.h
@@ -38,6 +38,7 @@ typedef unsigned int uint32_t;
#define ETH_PMT_WAKEUP 10
#define CECB_WAKEUP 11
#define ETH_PHY_GPIO 12
+#define GPIO_WAKEUP 13
/* wake up source*/
#define UDEFINED_WAKEUP_SRC (1<<0)
#define CHARGING_WAKEUP_SRC (1<<1)
@@ -51,6 +52,7 @@ typedef unsigned int uint32_t;
#define ETH_PMT_WAKEUP_SRC (1<<9)
#define CECB_WAKEUP_SRC (1<<10)
#define ETH_PHY_GPIO_SRC (1<<12)
+#define GPIO_WAKEUP_SRC (1<<13)
struct pwr_op {
void (*power_off_at_24M)(unsigned int);
diff --git a/board/hardkernel/odroidc4/firmware/scp_task/pwr_ctrl.c b/board/hardkernel/odroidc4/firmware/scp_task/pwr_ctrl.c
index 8e8c5a37ca..51e784c4f0 100644
--- a/board/hardkernel/odroidc4/firmware/scp_task/pwr_ctrl.c
+++ b/board/hardkernel/odroidc4/firmware/scp_task/pwr_ctrl.c
@@ -23,6 +23,9 @@
#ifdef CONFIG_CEC_WAKEUP
#include <cec_tx_reg.h>
#endif
+#ifdef CONFIG_GPIO_WAKEUP
+#include <gpio_key.h>
+#endif
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
@@ -132,6 +135,10 @@ static unsigned int detect_key(unsigned int suspend_from)
unsigned char adc_key_cnt = 0;
saradc_enable();
#endif
+#ifdef CONFIG_GPIO_WAKEUP
+ unsigned int is_gpiokey = 0;
+#endif
+
init_remote();
#ifdef CONFIG_CEC_WAKEUP
if (hdmi_cec_func_config & 0x1) {
@@ -140,6 +147,10 @@ static unsigned int detect_key(unsigned int suspend_from)
}
#endif
+#ifdef CONFIG_GPIO_WAKEUP
+ is_gpiokey = init_gpio_key();
+#endif
+
do {
#ifdef CONFIG_CEC_WAKEUP
if (!cec_msg.log_addr)
@@ -187,6 +198,12 @@ static unsigned int detect_key(unsigned int suspend_from)
exit_reason = ETH_PHY_GPIO;
}
+#ifdef CONFIG_GPIO_WAKEUP
+ if (is_gpiokey) {
+ if (gpio_detect_key())
+ exit_reason = GPIO_WAKEUP;
+ }
+#endif
if (exit_reason)
break;
else