aboutsummaryrefslogtreecommitdiff
path: root/platforms/bmc/palmetto.c
diff options
context:
space:
mode:
Diffstat (limited to 'platforms/bmc/palmetto.c')
-rw-r--r--platforms/bmc/palmetto.c186
1 files changed, 186 insertions, 0 deletions
diff --git a/platforms/bmc/palmetto.c b/platforms/bmc/palmetto.c
new file mode 100644
index 0000000..42905de
--- /dev/null
+++ b/platforms/bmc/palmetto.c
@@ -0,0 +1,186 @@
+/* Copyright 2013-2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <skiboot.h>
+#include <device.h>
+#include <console.h>
+#include <psi.h>
+#include <chip.h>
+#include <xscom.h>
+#include <ast.h>
+
+#include "bmc.h"
+
+/* UART1 config */
+#define UART_IO_BASE 0x3f8
+#define UART_IO_COUNT 8
+
+#define UART_LPC_IRQ 4
+
+static void palmetto_ext_irq(unsigned int chip_id __unused)
+{
+ uart_irq();
+}
+
+static void palmetto_init(void)
+{
+ /* Setup dummy console nodes */
+ if (dummy_console_enabled())
+ dummy_console_add_nodes();
+
+ /* Initialize AHB accesses via AST2400 */
+ ast_io_init();
+
+ /* Initialize PNOR/NVRAM */
+ pnor_init();
+}
+
+
+static void palmetto_fixup_dt_uart(struct dt_node *lpc)
+{
+ /*
+ * The official OF ISA/LPC binding is a bit odd, it prefixes
+ * the unit address for IO with "i". It uses 2 cells, the first
+ * one indicating IO vs. Memory space (along with bits to
+ * represent aliasing).
+ *
+ * We pickup that binding and add to it "2" as a indication
+ * of FW space.
+ */
+ struct dt_node *uart;
+ char namebuf[32];
+
+ /* First check if the UART is already there */
+ dt_for_each_child(lpc, uart) {
+ if (dt_node_is_compatible(uart, "ns16550"))
+ return;
+ }
+
+ /* Otherwise, add a node for it */
+ sprintf(namebuf, "serial@i%x", UART_IO_BASE);
+ uart = dt_new(lpc, namebuf);
+
+ dt_add_property_cells(uart, "reg",
+ 1, /* IO space */
+ UART_IO_BASE, UART_IO_COUNT);
+ dt_add_property_strings(uart, "compatible",
+ "ns16550",
+ "pnpPNP,501");
+ dt_add_property_cells(uart, "clock-frequency", 1843200);
+ dt_add_property_cells(uart, "current-speed", 115200);
+
+ /*
+ * This is needed by Linux for some obscure reasons,
+ * we'll eventually need to sanitize it but in the meantime
+ * let's make sure it's there
+ */
+ dt_add_property_strings(uart, "device_type", "serial");
+
+ /*
+ * Add interrupt. This simulates coming from HostBoot which
+ * does not know our interrupt numbering scheme. Instead, it
+ * just tells us which chip the interrupt is wired to, it will
+ * be the PSI "host error" interrupt of that chip. For now we
+ * assume the same chip as the LPC bus is on.
+ */
+ dt_add_property_cells(uart, "ibm,irq-chip-id", dt_get_chip_id(lpc));
+}
+
+static void palmetto_fixup_dt(void)
+{
+ struct dt_node *n, *primary_lpc = NULL;
+
+ /* Find the primary LPC bus */
+ dt_for_each_compatible(dt_root, n, "ibm,power8-lpc") {
+ if (!primary_lpc || dt_has_node_property(n, "primary", NULL))
+ primary_lpc = n;
+ if (dt_has_node_property(n, "#address-cells", NULL))
+ break;
+ }
+
+ if (!primary_lpc)
+ return;
+
+ /* Fixup the UART, that might be missing from HB */
+ palmetto_fixup_dt_uart(primary_lpc);
+
+ /* Force the dummy console for now */
+ force_dummy_console();
+}
+
+static void palmetto_fixup_psi_bar(void)
+{
+ struct proc_chip *chip = next_chip(NULL);
+ uint64_t psibar;
+
+ /* Read PSI BAR */
+ if (xscom_read(chip->id, 0x201090A, &psibar)) {
+ prerror("PLAT: Error reading PSI BAR\n");
+ return;
+ }
+ /* Already configured, bail out */
+ if (psibar & 1)
+ return;
+
+ /* Hard wire ... yuck */
+ psibar = 0x3fffe80000001;
+
+ printf("PLAT: Fixing up PSI BAR on chip %d BAR=%llx\n",
+ chip->id, psibar);
+
+ /* Now write it */
+ xscom_write(chip->id, 0x201090A, psibar);
+}
+
+static bool palmetto_probe(void)
+{
+ const char *model;
+
+ if (!dt_node_is_compatible(dt_root, "ibm,powernv"))
+ return false;
+
+ /* Temporary ... eventually we'll get that in compatible */
+ model = dt_prop_get_def(dt_root, "model", NULL);
+ if ((!model || !strstr(model, "palmetto")) &&
+ (!dt_node_is_compatible(dt_root, "ibm,palmetto")))
+ return false;
+
+ /* Hostboot's device-tree isn't quite right yet */
+ palmetto_fixup_dt();
+
+ /* Hostboot forgets to populate the PSI BAR */
+ palmetto_fixup_psi_bar();
+
+ /* Send external interrupts to me */
+ psi_set_external_irq_policy(EXTERNAL_IRQ_POLICY_SKIBOOT);
+
+ /* Configure UART1 on SuperIO */
+ ast_setup_uart1(UART_IO_BASE, UART_LPC_IRQ);
+
+ /* Setup UART and use it as console with interrupts */
+ uart_init(true);
+
+ return true;
+}
+
+DECLARE_PLATFORM(palmetto) = {
+ .name = "Palmetto",
+ .probe = palmetto_probe,
+ .init = palmetto_init,
+ .external_irq = palmetto_ext_irq,
+};
+