aboutsummaryrefslogtreecommitdiff
path: root/src/soc/nvidia/tegra
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/nvidia/tegra')
-rw-r--r--src/soc/nvidia/tegra/gpio.c240
-rw-r--r--src/soc/nvidia/tegra/gpio.h63
-rw-r--r--src/soc/nvidia/tegra/pingroup.c35
-rw-r--r--src/soc/nvidia/tegra/pingroup.h43
-rw-r--r--src/soc/nvidia/tegra/pinmux.c35
-rw-r--r--src/soc/nvidia/tegra/pinmux.h44
6 files changed, 460 insertions, 0 deletions
diff --git a/src/soc/nvidia/tegra/gpio.c b/src/soc/nvidia/tegra/gpio.c
new file mode 100644
index 0000000000..d4b5bddd49
--- /dev/null
+++ b/src/soc/nvidia/tegra/gpio.c
@@ -0,0 +1,240 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <arch/io.h>
+#include <console/console.h>
+#include <soc/addressmap.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "gpio.h"
+#include "pinmux.h"
+
+static void gpio_input_common(int gpio_index, int pinmux_index,
+ uint32_t pconfig)
+{
+ pconfig |= PINMUX_INPUT_ENABLE;
+ gpio_set_int_enable(gpio_index, 0);
+ gpio_set_mode(gpio_index, GPIO_MODE_GPIO);
+ gpio_set_out_enable(gpio_index, 0);
+ pinmux_set_config(pinmux_index, pconfig);
+}
+
+void gpio_input(int gpio_index, int pinmux_index)
+{
+ gpio_input_common(gpio_index, pinmux_index, PINMUX_PULL_NONE);
+}
+
+void gpio_input_pullup(int gpio_index, int pinmux_index)
+{
+ gpio_input_common(gpio_index, pinmux_index, PINMUX_PULL_UP);
+}
+
+void gpio_input_pulldown(int gpio_index, int pinmux_index)
+{
+ gpio_input_common(gpio_index, pinmux_index, PINMUX_PULL_DOWN);
+}
+
+void gpio_output(int gpio_index, int pinmux_index, int value)
+{
+ uint32_t pconfig = PINMUX_PULL_NONE;
+
+ pinmux_set_config(pinmux_index, pconfig | PINMUX_TRISTATE);
+ gpio_set_int_enable(gpio_index, 0);
+ gpio_set_mode(gpio_index, GPIO_MODE_GPIO);
+ gpio_set_out_enable(gpio_index, 1);
+ gpio_set_out_value(gpio_index, value);
+ pinmux_set_config(pinmux_index, pconfig);
+}
+
+enum {
+ GPIO_GPIOS_PER_PORT = 8,
+ GPIO_PORTS_PER_BANK = 4,
+ GPIO_BANKS = 8,
+
+ GPIO_GPIOS_PER_BANK = GPIO_GPIOS_PER_PORT * GPIO_PORTS_PER_BANK,
+ GPIO_GPIOS = GPIO_BANKS * GPIO_GPIOS_PER_BANK
+};
+
+struct gpio_bank {
+ // Values
+ uint32_t config[GPIO_PORTS_PER_BANK];
+ uint32_t out_enable[GPIO_PORTS_PER_BANK];
+ uint32_t out_value[GPIO_PORTS_PER_BANK];
+ uint32_t in_value[GPIO_PORTS_PER_BANK];
+ uint32_t int_status[GPIO_PORTS_PER_BANK];
+ uint32_t int_enable[GPIO_PORTS_PER_BANK];
+ uint32_t int_level[GPIO_PORTS_PER_BANK];
+ uint32_t int_clear[GPIO_PORTS_PER_BANK];
+
+ // Masks
+ uint32_t config_mask[GPIO_PORTS_PER_BANK];
+ uint32_t out_enable_mask[GPIO_PORTS_PER_BANK];
+ uint32_t out_value_mask[GPIO_PORTS_PER_BANK];
+ uint32_t in_value_mask[GPIO_PORTS_PER_BANK];
+ uint32_t int_status_mask[GPIO_PORTS_PER_BANK];
+ uint32_t int_enable_mask[GPIO_PORTS_PER_BANK];
+ uint32_t int_level_mask[GPIO_PORTS_PER_BANK];
+ uint32_t int_clear_mask[GPIO_PORTS_PER_BANK];
+};
+
+static const struct gpio_bank *gpio_banks = (void *)TEGRA_GPIO_BASE;
+
+static uint32_t gpio_read_port(int index, size_t offset)
+{
+ int bank = index / GPIO_GPIOS_PER_BANK;
+ int port = (index - bank * GPIO_GPIOS_PER_BANK) / GPIO_GPIOS_PER_PORT;
+
+ return read32((uint8_t *)&gpio_banks[bank] + offset +
+ port * sizeof(uint32_t));
+}
+
+static void gpio_write_port(int index, size_t offset,
+ uint32_t mask, uint32_t value)
+{
+ int bank = index / GPIO_GPIOS_PER_BANK;
+ int port = (index - bank * GPIO_GPIOS_PER_BANK) / GPIO_GPIOS_PER_PORT;
+
+ uint32_t reg = read32((uint8_t *)&gpio_banks[bank] + offset +
+ port * sizeof(uint32_t));
+ uint32_t new_reg = (reg & ~mask) | (value & mask);
+
+ if (new_reg != reg) {
+ write32(new_reg, (uint8_t *)&gpio_banks[bank] + offset +
+ port * sizeof(uint32_t));
+ }
+}
+
+void gpio_set_mode(int gpio_index, enum gpio_mode mode)
+{
+ int bit = gpio_index % GPIO_GPIOS_PER_PORT;
+ gpio_write_port(gpio_index, offsetof(struct gpio_bank, config),
+ 1 << bit, mode ? (1 << bit) : 0);
+}
+
+int gpio_get_mode(int gpio_index)
+{
+ int bit = gpio_index % GPIO_GPIOS_PER_PORT;
+ uint32_t port = gpio_read_port(gpio_index,
+ offsetof(struct gpio_bank, config));
+ return (port & (1 << bit)) != 0;
+}
+
+void gpio_set_lock(int gpio_index)
+{
+ int bit = gpio_index % GPIO_GPIOS_PER_PORT + GPIO_GPIOS_PER_PORT;
+ gpio_write_port(gpio_index, offsetof(struct gpio_bank, config),
+ 1 << bit, 1 << bit);
+}
+
+int gpio_get_lock(int gpio_index)
+{
+ int bit = gpio_index % GPIO_GPIOS_PER_PORT + GPIO_GPIOS_PER_PORT;
+ uint32_t port = gpio_read_port(gpio_index,
+ offsetof(struct gpio_bank, config));
+ return (port & (1 << bit)) != 0;
+}
+
+void gpio_set_out_enable(int gpio_index, int enable)
+{
+ int bit = gpio_index % GPIO_GPIOS_PER_PORT;
+ gpio_write_port(gpio_index, offsetof(struct gpio_bank, out_enable),
+ 1 << bit, enable ? (1 << bit) : 0);
+}
+
+int gpio_get_out_enable(int gpio_index)
+{
+ int bit = gpio_index % GPIO_GPIOS_PER_PORT;
+ uint32_t port = gpio_read_port(gpio_index,
+ offsetof(struct gpio_bank, out_enable));
+ return (port & (1 << bit)) != 0;
+}
+
+void gpio_set_out_value(int gpio_index, int value)
+{
+ int bit = gpio_index % GPIO_GPIOS_PER_PORT;
+ gpio_write_port(gpio_index, offsetof(struct gpio_bank, out_value),
+ 1 << bit, value ? (1 << bit) : 0);
+}
+
+int gpio_get_out_value(int gpio_index)
+{
+ int bit = gpio_index % GPIO_GPIOS_PER_PORT;
+ uint32_t port = gpio_read_port(gpio_index,
+ offsetof(struct gpio_bank, out_value));
+ return (port & (1 << bit)) != 0;
+}
+
+int gpio_get_in_value(int gpio_index)
+{
+ int bit = gpio_index % GPIO_GPIOS_PER_PORT;
+ uint32_t port = gpio_read_port(gpio_index,
+ offsetof(struct gpio_bank, in_value));
+ return (port & (1 << bit)) != 0;
+}
+
+int gpio_get_int_status(int gpio_index)
+{
+ int bit = gpio_index % GPIO_GPIOS_PER_PORT;
+ uint32_t port = gpio_read_port(gpio_index,
+ offsetof(struct gpio_bank, int_status));
+ return (port & (1 << bit)) != 0;
+}
+
+void gpio_set_int_enable(int gpio_index, int enable)
+{
+ int bit = gpio_index % GPIO_GPIOS_PER_PORT;
+ gpio_write_port(gpio_index, offsetof(struct gpio_bank, int_enable),
+ 1 << bit, enable ? (1 << bit) : 0);
+}
+
+int gpio_get_int_enable(int gpio_index)
+{
+ int bit = gpio_index % GPIO_GPIOS_PER_PORT;
+ uint32_t port = gpio_read_port(gpio_index,
+ offsetof(struct gpio_bank, int_enable));
+ return (port & (1 << bit)) != 0;
+}
+
+void gpio_set_int_level(int gpio_index, int high_rise, int edge, int delta)
+{
+ int bit = gpio_index % GPIO_GPIOS_PER_PORT;
+ uint32_t value = (high_rise ? (0x000001 << bit) : 0) |
+ (edge ? (0x000100 << bit) : 0) |
+ (delta ? (0x010000 << bit) : 0);
+ gpio_write_port(gpio_index, offsetof(struct gpio_bank, config),
+ 0x010101 << bit, value);
+}
+
+void gpio_get_int_level(int gpio_index, int *high_rise, int *edge, int *delta)
+{
+ int bit = gpio_index % GPIO_GPIOS_PER_PORT;
+ uint32_t port = gpio_read_port(gpio_index,
+ offsetof(struct gpio_bank, int_level));
+ *high_rise = ((port & (0x000001 << bit)) != 0);
+ *edge = ((port & (0x000100 << bit)) != 0);
+ *delta = ((port & (0x010000 << bit)) != 0);
+}
+
+void gpio_set_int_clear(int gpio_index)
+{
+ int bit = gpio_index % GPIO_GPIOS_PER_PORT;
+ gpio_write_port(gpio_index, offsetof(struct gpio_bank, int_clear),
+ 1 << bit, 1 << bit);
+}
diff --git a/src/soc/nvidia/tegra/gpio.h b/src/soc/nvidia/tegra/gpio.h
new file mode 100644
index 0000000000..b62dc90906
--- /dev/null
+++ b/src/soc/nvidia/tegra/gpio.h
@@ -0,0 +1,63 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA_GPIO_H__
+#define __SOC_NVIDIA_TEGRA_GPIO_H__
+
+#include <stdint.h>
+
+/* Higher level functions for common GPIO configurations. */
+
+void gpio_input(int gpio_index, int pinmux_index);
+void gpio_input_pullup(int gpio_index, int pinmux_index);
+void gpio_input_pulldown(int gpio_index, int pinmux_index);
+void gpio_output(int gpio_index, int pinmux_index, int value);
+
+/* Functions to modify specific GPIO control values. */
+
+enum gpio_mode {
+ GPIO_MODE_SPIO = 0,
+ GPIO_MODE_GPIO = 1
+};
+void gpio_set_mode(int gpio_index, enum gpio_mode);
+int gpio_get_mode(int gpio_index);
+
+// Lock a GPIO with extreme caution since they can't be unlocked.
+void gpio_set_lock(int gpio_index);
+int gpio_get_lock(int gpio_index);
+
+void gpio_set_out_enable(int gpio_index, int enable);
+int gpio_get_out_enable(int gpio_index);
+
+void gpio_set_out_value(int gpio_index, int value);
+int gpio_get_out_value(int gpio_index);
+
+int gpio_get_in_value(int gpio_index);
+
+int gpio_get_int_status(int gpio_index);
+
+void gpio_set_int_enable(int gpio_index, int enable);
+int gpio_get_int_enable(int gpio_index);
+
+void gpio_set_int_level(int gpio_index, int high_rise, int edge, int delta);
+void gpio_get_int_level(int gpio_index, int *high_rise, int *edge, int *delta);
+
+void gpio_set_int_clear(int gpio_index);
+
+#endif /* __SOC_NVIDIA_TEGRA_GPIO_H__ */
diff --git a/src/soc/nvidia/tegra/pingroup.c b/src/soc/nvidia/tegra/pingroup.c
new file mode 100644
index 0000000000..858cb44e34
--- /dev/null
+++ b/src/soc/nvidia/tegra/pingroup.c
@@ -0,0 +1,35 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <arch/io.h>
+#include <soc/addressmap.h>
+
+#include "pingroup.h"
+
+static uint32_t *pingroup_regs = (void *)TEGRA_APB_PINGROUP_BASE;
+
+void pingroup_set_config(int group_index, uint32_t config)
+{
+ write32(config, &pingroup_regs[group_index]);
+}
+
+uint32_t pingroup_get_config(int group_index)
+{
+ return read32(&pingroup_regs[group_index]);
+}
diff --git a/src/soc/nvidia/tegra/pingroup.h b/src/soc/nvidia/tegra/pingroup.h
new file mode 100644
index 0000000000..f04b66541d
--- /dev/null
+++ b/src/soc/nvidia/tegra/pingroup.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA_PINGROUP_H__
+#define __SOC_NVIDIA_TEGRA_PINGROUP_H__
+
+#include <stdint.h>
+
+void pingroup_set_config(int group_index, uint32_t config);
+uint32_t pingroup_get_config(int group_index);
+
+enum {
+ PINGROUP_HSM = 1 << 2,
+ PINGROUP_SCHMT = 1 << 3,
+ PINGROUP_LPMD_SHIFT = 4,
+ PINGROUP_LPMD_MASK = 3 << 4,
+ PINGROUP_DRVDN_SHIFT = 12,
+ PINGROUP_DRVDN_MASK = 0x7f << 12,
+ PINGROUP_DRVUP_SHIFT = 20,
+ PINGROUP_DRVUP_MASK = 0x7f << 20,
+ PINGROUP_SLWR_SHIFT = 28,
+ PINGROUP_SLWR_MASK = 0x3 << 28,
+ PINGROUP_SLWF_SHIFT = 30,
+ PINGROUP_SLWF_MASK = 0x3 << 30
+};
+
+#endif /* __SOC_NVIDIA_TEGRA_PINGROUP_H__ */
diff --git a/src/soc/nvidia/tegra/pinmux.c b/src/soc/nvidia/tegra/pinmux.c
new file mode 100644
index 0000000000..6e4b3ff195
--- /dev/null
+++ b/src/soc/nvidia/tegra/pinmux.c
@@ -0,0 +1,35 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <arch/io.h>
+#include <soc/addressmap.h>
+
+#include "pinmux.h"
+
+static uint32_t *pinmux_regs = (void *)TEGRA_APB_PINMUX_BASE;
+
+void pinmux_set_config(int pin_index, uint32_t config)
+{
+ write32(config, &pinmux_regs[pin_index]);
+}
+
+uint32_t pinmux_get_config(int pin_index)
+{
+ return read32(&pinmux_regs[pin_index]);
+}
diff --git a/src/soc/nvidia/tegra/pinmux.h b/src/soc/nvidia/tegra/pinmux.h
new file mode 100644
index 0000000000..e42135d9a4
--- /dev/null
+++ b/src/soc/nvidia/tegra/pinmux.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA_PINMUX_H__
+#define __SOC_NVIDIA_TEGRA_PINMUX_H__
+
+#include <stdint.h>
+
+void pinmux_set_config(int pin_index, uint32_t config);
+uint32_t pinmux_get_config(int pin_index);
+
+enum {
+ PINMUX_FUNC_MASK = 3 << 0,
+
+ PINMUX_PULL_MASK = 3 << 2,
+ PINMUX_PULL_NONE = 0 << 2,
+ PINMUX_PULL_DOWN = 1 << 2,
+ PINMUX_PULL_UP = 2 << 2,
+
+ PINMUX_TRISTATE = 1 << 4,
+ PINMUX_INPUT_ENABLE = 1 << 5,
+ PINMUX_OPEN_DRAIN = 1 << 6,
+ PINMUX_LOCK = 1 << 7,
+ PINMUX_IO_RESET = 1 << 8,
+ PINMUX_RCV_SEL = 1 << 9
+};
+
+#endif /* __SOC_NVIDIA_TEGRA_PINMUX_H__ */