[msm8053] Work in progress on msm8053 support
Execution makes it through the boot shim and into the kernel,
but mysteriously resets after that.
NOTES:
Device is flashed via fastboot using scripts/flash-msm8x53-som
Power cycling with volume down button pressed gets you into fastboot.
Serial debug access is done via special Y-cable that connects to the USB-C port
Connect to /dev/ttyUSB0 @ 115200
Finally, if the device fails to boot too many times in a row it will start booting off
the boot_b partition (which still contains Linux) instead of boot_a, where Zircon is flashed.
to fix that, you can reset the counters by doing:
fastboot flash partition kernel/target/arm64/board/msm8x53-som/partition-table.img
TEST: attempt to boot on msm8053 hardware as described above
Change-Id: I281eb98273952889a85a9e23a8914a7c39f4a2c7
diff --git a/kernel/dev/uart/msm/rules.mk b/kernel/dev/uart/msm/rules.mk
new file mode 100644
index 0000000..7408656
--- /dev/null
+++ b/kernel/dev/uart/msm/rules.mk
@@ -0,0 +1,17 @@
+# Copyright 2019 The Fuchsia Authors
+# Use of this source code is governed by a MIT-style
+# license that can be found in the LICENSE file or at
+# https://opensource.org/licenses/MIT
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS += \
+ $(LOCAL_DIR)/uart.cpp
+
+MODULE_DEPS += \
+ kernel/dev/pdev \
+ kernel/dev/pdev/uart \
+
+include make/module.mk
diff --git a/kernel/dev/uart/msm/uart.cpp b/kernel/dev/uart/msm/uart.cpp
new file mode 100644
index 0000000..e12180e
--- /dev/null
+++ b/kernel/dev/uart/msm/uart.cpp
@@ -0,0 +1,340 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file or at
+// https://opensource.org/licenses/MIT
+
+// TODO(gkalsi): Unify the two UART codepaths and use the port parameter to
+// select between the real uart and the miniuart.
+
+#include <arch/arm64/periphmap.h>
+#include <dev/interrupt.h>
+#include <dev/uart.h>
+#include <kernel/thread.h>
+#include <lib/cbuf.h>
+#include <lib/debuglog.h>
+#include <pdev/driver.h>
+#include <pdev/uart.h>
+#include <platform/debug.h>
+#include <reg.h>
+#include <stdio.h>
+#include <trace.h>
+#include <zircon/boot/driver-config.h>
+
+// clang-format off
+
+#define UART_MR1 0x0000
+#define UART_MR1_RX_RDY_CTL (1 << 7)
+
+#define UART_MR2 0x0004
+#define UART_DM_IPR 0x0018
+#define UART_DM_DMRX 0x0034
+#define UART_DM_N0_CHARS_FOR_TX 0x0040
+
+#define UART_DM_SR 0x00A4
+#define UART_DM_SR_RXRDY (1 << 0)
+#define UART_DM_SR_RXFULL (1 << 1)
+#define UART_DM_SR_TXRDY (1 << 2)
+#define UART_DM_SR_TXEMT (1 << 3)
+#define UART_DM_SR_OVERRUN (1 << 4)
+#define UART_DM_SR_PAR_FRAME_ERR (1 << 5)
+#define UART_DM_SR_RX_BREAK (1 << 6)
+#define UART_DM_SR_HUNT_CHAR (1 << 7)
+
+#define UART_DM_CR 0x00A8
+#define UART_DM_CR_RX_EN (1 << 0)
+#define UART_DM_CR_RX_DISABLE (1 << 1)
+#define UART_DM_CR_TX_EN (1 << 2)
+#define UART_DM_CR_TX_DISABLE (1 << 3)
+
+#define UART_DM_CR_CMD_RESET_RX (1 << 4)
+#define UART_DM_CR_CMD_RESET_TX (2 << 4)
+#define UART_DM_CR_CMD_RESET_ERR (3 << 4)
+#define UART_DM_CR_CMD_RESET_BRK_CHG_INT (4 << 4)
+#define UART_DM_CR_CMD_START_BRK (5 << 4)
+#define UART_DM_CR_CMD_STOP_BRK (6 << 4)
+#define UART_DM_CR_CMD_RESET_CTS_N (7 << 4)
+#define UART_DM_CR_CMD_RESET_STALE_INT (8 << 4)
+#define UART_DM_CR_CMD_SET_RFR (13 << 4)
+#define UART_DM_CR_CMD_RESET_RFR (14 << 4)
+#define UART_DM_CR_CMD_CLEAR_TX_ERROR (16 << 4)
+#define UART_DM_CR_CMD_CLEAR_TX_DONE (17 << 4)
+#define UART_DM_CR_CMD_RESET_BRK_START_INT (18 << 4)
+#define UART_DM_CR_CMD_RESET_BRK_END_INT (19 << 4)
+#define UART_DM_CR_CMD_RESET_PAR_FRAME_ERR_INT (20 << 4)
+#define UART_DM_CR_CMD_CLEAR_TX_WR_ERROR_IRQ (25 << 4)
+#define UART_DM_CR_CMD_CLEAR_RX_RD_ERROR_IRQ (26 << 4)
+#define UART_DM_CR_CMD_CLEAR_TX_COMP_IRQ (27 << 4)
+#define UART_DM_CR_CMD_CLEAR_WWT_IRQ (28 << 4)
+#define UART_DM_CR_CMD_CLEAR_NO_FINISH_CMD_VIO_IRQ (30 << 4)
+
+#define UART_DM_CR_CMD_RESET_TX_READY (3 << 8)
+#define UART_DM_CR_CMD_FORCE_STALE (4 << 8)
+#define UART_DM_CR_CMD_ENABLE_STALE_EVENT (5 << 8)
+#define UART_DM_CR_CMD_DISABLE_STALE_EVENT (6 << 8)
+
+#define UART_DM_RXFS 0x0050
+#define UART_DM_RXFS_RX_BUFFER_STATE(r) ((r >> 7) & 7)
+#define UART_DM_RXFS_FIFO_STATE(r) ((r >> 14) | (r & 0x3F))
+
+#define UART_DM_MISR 0x00AC
+#define UART_DM_IMR 0x00B0
+#define UART_DM_ISR 0x00B4
+
+#define UART_IRQ_TXLEV (1 << 0)
+#define UART_IRQ_RXHUNT (1 << 1)
+#define UART_IRQ_RXBREAK_CHANGE (1 << 2)
+#define UART_IRQ_RXSTALE (1 << 3)
+#define UART_IRQ_RXLEV (1 << 4)
+#define UART_IRQ_DELTA_CTS (1 << 5)
+#define UART_IRQ_CURRENT_CTS (1 << 6)
+#define UART_IRQ_TX_READY (1 << 7)
+#define UART_IRQ_TX_ERROR (1 << 8)
+#define UART_IRQ_TX_DONE (1 << 9)
+#define UART_IRQ_RXBREAK_START (1 << 10)
+#define UART_IRQ_RXBREAK_END (1 << 11)
+#define UART_IRQ_PAR_FRAME_ERR_IRQ (1 << 12)
+#define UART_IRQ_TX_WR_ERROR_IRQ (1 << 13)
+#define UART_IRQ_RX_RD_ERROR_IRQ (1 << 14)
+#define UART_IRQ_TXCOMP_IRQ (1 << 15)
+#define UART_IRQ_WWT_IRQ (1 << 16)
+#define UART_IRQ_NO_FINISH_CMD_VIOL (1 << 17)
+
+#define UART_DM_TF 0x0100
+#define UART_DM_RF(n) (0x0140 + 4 * (n))
+
+#define RXBUF_SIZE 128
+
+// clang-format on
+
+// values read from zbi
+static uint64_t uart_base = 0;
+static uint32_t uart_irq = 0;
+
+static cbuf_t uart_rx_buf;
+
+static bool uart_tx_irq_enabled = false;
+static event_t uart_dputc_event = EVENT_INITIAL_VALUE(uart_dputc_event,
+ true,
+ EVENT_FLAG_AUTOUNSIGNAL);
+
+static spin_lock_t uart_spinlock = SPIN_LOCK_INITIAL_VALUE;
+
+static inline uint32_t uart_read(int offset) {
+ return readl(uart_base + offset);
+}
+
+static inline void uart_write(uint32_t val, int offset) {
+ writel(val, uart_base + offset);
+}
+
+static inline void yield(void)
+{
+ __asm__ volatile("yield" ::: "memory");
+}
+
+// panic-time getc/putc
+static int msm_pputc(char c) {
+ if (!uart_base) {
+ return -1;
+ }
+
+ // spin while fifo is full
+ while (!(uart_read(UART_DM_SR) & UART_DM_SR_TXEMT)) {
+ yield();
+ }
+ uart_write(UART_DM_CR_CMD_RESET_TX_READY, UART_DM_N0_CHARS_FOR_TX);
+ uart_write(1, UART_DM_N0_CHARS_FOR_TX);
+ uart_read(UART_DM_N0_CHARS_FOR_TX);
+
+ // wait for TX ready
+ while (!(uart_read(UART_DM_SR) & UART_DM_SR_TXRDY)) {
+ yield();
+ }
+
+ uart_write(c, UART_DM_TF);
+
+ return 1;
+}
+
+static int msm_pgetc(void)
+{
+ cbuf_t* rxbuf = &uart_rx_buf;
+
+ char c;
+ int count = 0;
+ uint32_t val, rxfs, sr;
+ char* bytes;
+
+ // see if we have chars left from previous read
+ if (cbuf_read_char(rxbuf, &c, false) == 1) {
+ return c;
+ }
+
+ if ((uart_read(UART_DM_SR) & UART_DM_SR_OVERRUN)) {
+ uart_write(UART_DM_CR_CMD_RESET_ERR, UART_DM_CR);
+ }
+
+ do {
+ rxfs = uart_read(UART_DM_RXFS);
+ sr = uart_read(UART_DM_SR);
+ count = UART_DM_RXFS_RX_BUFFER_STATE(rxfs);
+ if (!(sr & UART_DM_SR_RXRDY) && !count) {
+ return -1;
+ }
+ } while (count == 0);
+
+ uart_write(UART_DM_CR_CMD_FORCE_STALE, UART_DM_CR);
+ val = uart_read(UART_DM_RF(0));
+ uart_read(UART_DM_RF(1));
+
+ uart_write(UART_DM_CR_CMD_RESET_STALE_INT, UART_DM_CR);
+ uart_write(0xffffff, UART_DM_DMRX);
+
+ bytes = (char*)&val;
+ c = bytes[0];
+
+ // save remaining chars for next call
+ for (int i = 1; i < count; i++) {
+ cbuf_write_char(rxbuf, bytes[i]);
+ }
+
+ return c;
+}
+
+static interrupt_eoi uart_irq_handler(void* arg) {
+ uint32_t misr = uart_read(UART_DM_MISR);
+
+ while (uart_read(UART_DM_SR) & UART_DM_SR_RXRDY) {
+ uint32_t rxfs = uart_read(UART_DM_RXFS);
+ // count is number of words in RX fifo that have data
+ int count = UART_DM_RXFS_FIFO_STATE(rxfs);
+
+ for (int i = 0; i < count; i++) {
+ uint32_t val = uart_read(UART_DM_RF(0));
+ char* bytes = (char *)&val;
+
+ for (int j = 0; j < 4; j++) {
+ // Unfortunately there is no documented way to get number of bytes in each word
+ // so we just need to ignore zero bytes here.
+ // Apparently this problem doesn't exist in DMA mode.
+ char ch = bytes[j];
+ if (ch) {
+ cbuf_write_char(&uart_rx_buf, ch);
+ } else {
+ break;
+ }
+ }
+ }
+ }
+
+ if (misr & UART_IRQ_RXSTALE) {
+ uart_write(UART_DM_CR_CMD_RESET_STALE_INT, UART_DM_CR);
+ }
+
+ // ask to receive more
+ uart_write(0xFFFFFF, UART_DM_DMRX);
+ uart_write(UART_DM_CR_CMD_ENABLE_STALE_EVENT, UART_DM_CR);
+
+ return IRQ_EOI_DEACTIVATE;
+}
+
+static void msm_uart_init(const void* driver_data, uint32_t length) {
+ uint32_t temp;
+
+ // disable interrupts
+ uart_write(0, UART_DM_IMR);
+
+ uart_write(UART_DM_CR_TX_EN | UART_DM_CR_RX_EN, UART_DM_CR);
+ uart_write(UART_DM_CR_CMD_RESET_TX, UART_DM_CR);
+ uart_write(UART_DM_CR_CMD_RESET_RX, UART_DM_CR);
+ uart_write(UART_DM_CR_CMD_RESET_ERR, UART_DM_CR);
+ uart_write(UART_DM_CR_CMD_RESET_BRK_CHG_INT, UART_DM_CR);
+ uart_write(UART_DM_CR_CMD_RESET_CTS_N, UART_DM_CR);
+ uart_write(UART_DM_CR_CMD_SET_RFR, UART_DM_CR);
+ uart_write(UART_DM_CR_CMD_CLEAR_TX_DONE, UART_DM_CR);
+
+ uart_write(0xFFFFFF, UART_DM_DMRX);
+ uart_write(UART_DM_CR_CMD_ENABLE_STALE_EVENT, UART_DM_CR);
+
+ temp = uart_read(UART_MR1);
+ temp |= UART_MR1_RX_RDY_CTL;
+ uart_write(temp, UART_MR1);
+
+ cbuf_initialize(&uart_rx_buf, RXBUF_SIZE);
+
+ // enable RX interrupt
+ uart_write(UART_IRQ_RXSTALE, UART_DM_IMR);
+
+ register_int_handler(uart_irq, &uart_irq_handler, nullptr);
+ unmask_interrupt(uart_irq);
+}
+
+static int msm_getc(bool wait) {
+ char ch;
+ size_t count = cbuf_read_char(&uart_rx_buf, &ch, wait);
+ return (count == 1 ? ch : -1);
+}
+
+static void msm_start_panic(void) {
+ uart_tx_irq_enabled = false;
+}
+
+static void msm_dputs(const char* str, size_t len,
+ bool block, bool map_NL) {
+ spin_lock_saved_state_t state;
+ bool copied_CR = false;
+
+ if (!uart_base) {
+ return;
+ }
+ if (!uart_tx_irq_enabled) {
+ block = false;
+ }
+ spin_lock_irqsave(&uart_spinlock, state);
+
+ while (len > 0) {
+ // is FIFO full?
+ while (!(uart_read(UART_DM_SR) & UART_DM_SR_TXEMT)) {
+ spin_unlock_irqrestore(&uart_spinlock, state);
+ if (block) {
+ // TODO(voydanoff) Enable TX interrupt.
+ event_wait(&uart_dputc_event);
+ } else {
+ arch_spinloop_pause();
+ }
+ spin_lock_irqsave(&uart_spinlock, state);
+ }
+ if (*str == '\n' && map_NL && !copied_CR) {
+ copied_CR = true;
+ msm_pputc('\r');
+ } else {
+ copied_CR = false;
+ msm_pputc(*str++);
+ len--;
+ }
+ }
+ spin_unlock_irqrestore(&uart_spinlock, state);
+}
+
+static const struct pdev_uart_ops uart_ops = {
+ .getc = msm_getc,
+ .pputc = msm_pputc,
+ .pgetc = msm_pgetc,
+ .start_panic = msm_start_panic,
+ .dputs = msm_dputs,
+};
+
+static void msm_uart_init_early(const void* driver_data, uint32_t length) {
+ ASSERT(length >= sizeof(dcfg_simple_t));
+ auto driver = static_cast<const dcfg_simple_t*>(driver_data);
+ uart_base = periph_paddr_to_vaddr(driver->mmio_phys);
+ uart_irq = driver->irq;
+ ASSERT(uart_base);
+ ASSERT(uart_irq);
+
+ pdev_register_uart(&uart_ops);
+}
+
+LK_PDEV_INIT(msm_uart_init_early, KDRV_MSM_UART, msm_uart_init_early, LK_INIT_LEVEL_PLATFORM_EARLY);
+LK_PDEV_INIT(msm_uart_init, KDRV_MSM_UART, msm_uart_init, LK_INIT_LEVEL_PLATFORM);
diff --git a/kernel/platform/generic-arm/rules.mk b/kernel/platform/generic-arm/rules.mk
index 475f093..04522c7 100644
--- a/kernel/platform/generic-arm/rules.mk
+++ b/kernel/platform/generic-arm/rules.mk
@@ -33,6 +33,7 @@
kernel/dev/power/hisi \
kernel/dev/psci \
kernel/dev/uart/amlogic_s905 \
+ kernel/dev/uart/msm \
kernel/dev/uart/mt8167 \
kernel/dev/uart/nxp-imx \
kernel/dev/uart/pl011 \
diff --git a/kernel/target/arm64/board/msm8x53-som/boot-shim-config.h b/kernel/target/arm64/board/msm8x53-som/boot-shim-config.h
new file mode 100644
index 0000000..e445e4e
--- /dev/null
+++ b/kernel/target/arm64/board/msm8x53-som/boot-shim-config.h
@@ -0,0 +1,118 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#define HAS_DEVICE_TREE 1
+
+static const zbi_cpu_config_t cpu_config = {
+ .cluster_count = 2,
+ .clusters = {
+ {
+ .cpu_count = 4,
+ },
+ {
+ .cpu_count = 4,
+ },
+ },
+};
+
+static const zbi_mem_range_t mem_config[] = {
+ {
+ .type = ZBI_MEM_RANGE_RAM,
+ .paddr = 0x80000000,
+ .length = 0x80000000, // 2GB
+ },
+ {
+ .type = ZBI_MEM_RANGE_PERIPHERAL,
+ // This is not the entire peripheral range, but enough to cover what we use in the kernel.
+ .paddr = 0x00000000,
+ .length = 0x10000000,
+ },
+ {
+ // other_ext_mem: other_ext_region@0
+ .type = ZBI_MEM_RANGE_RESERVED,
+ .paddr = 0x85b00000,
+ .length = 0xd00000,
+ },
+ {
+ // modem_mem: modem_region@0
+ .type = ZBI_MEM_RANGE_RESERVED,
+ .paddr = 0x86c00000,
+ .length = 0x6a00000,
+ },
+ {
+ // adsp_fw_mem: adsp_fw_region@0
+ .type = ZBI_MEM_RANGE_RESERVED,
+ .paddr = 0x8d600000,
+ .length = 0x1100000,
+ },
+ {
+ // wcnss_fw_mem: wcnss_fw_region@0
+ .type = ZBI_MEM_RANGE_RESERVED,
+ .paddr = 0x8e700000,
+ .length = 0x700000,
+ },
+ {
+ // dfps_data_mem: dfps_data_mem@0
+ .type = ZBI_MEM_RANGE_RESERVED,
+ .paddr = 0x90000000,
+ .length = 0x1000,
+ },
+ {
+ // cont_splash_mem: splash_region@0
+ .type = ZBI_MEM_RANGE_RESERVED,
+ .paddr = 0x90001000,
+ .length = 0x13ff000,
+ },
+};
+
+static const dcfg_simple_t uart_driver = {
+ .mmio_phys = 0x078af000,
+ .irq = 107 + 32,
+};
+
+static const dcfg_arm_gicv2_driver_t gicv2_driver = {
+ .mmio_phys = 0x0b000000,
+ .gicd_offset = 0x00000,
+ .gicc_offset = 0x1000,
+ .ipi_base = 5,
+};
+
+static const dcfg_arm_psci_driver_t psci_driver = {
+ .use_hvc = false,
+};
+
+static const dcfg_arm_generic_timer_driver_t timer_driver = {
+ .irq_phys = 16 + 14, // PHYS_NONSECURE_PPI: GIC_PPI 14
+ .irq_virt = 16 + 11, // VIRT_PPI: GIC_PPI 11
+};
+
+static const zbi_platform_id_t platform_id = {
+ .vid = PDEV_VID_QUALCOMM,
+ .pid = PDEV_PID_QUALCOMM_MSM8X53,
+ .board_name = "msm8x53-som",
+};
+
+static void append_board_boot_item(zbi_header_t* bootdata) {
+ // add CPU configuration
+ append_boot_item(bootdata, ZBI_TYPE_CPU_CONFIG, 0, &cpu_config,
+ sizeof(zbi_cpu_config_t) +
+ sizeof(zbi_cpu_cluster_t) * cpu_config.cluster_count);
+
+ // add memory configuration
+ append_boot_item(bootdata, ZBI_TYPE_MEM_CONFIG, 0, &mem_config,
+ sizeof(zbi_mem_range_t) * countof(mem_config));
+
+ // add kernel drivers
+ append_boot_item(bootdata, ZBI_TYPE_KERNEL_DRIVER, KDRV_MSM_UART, &uart_driver,
+ sizeof(uart_driver));
+ append_boot_item(bootdata, ZBI_TYPE_KERNEL_DRIVER, KDRV_ARM_GIC_V2, &gicv2_driver,
+ sizeof(gicv2_driver));
+ append_boot_item(bootdata, ZBI_TYPE_KERNEL_DRIVER, KDRV_ARM_PSCI, &psci_driver,
+ sizeof(psci_driver));
+ append_boot_item(bootdata, ZBI_TYPE_KERNEL_DRIVER, KDRV_ARM_GENERIC_TIMER, &timer_driver,
+ sizeof(timer_driver));
+
+ // add platform ID
+ append_boot_item(bootdata, ZBI_TYPE_PLATFORM_ID, 0, &platform_id, sizeof(platform_id));
+}
diff --git a/kernel/target/arm64/board/msm8x53-som/device-tree.dtb b/kernel/target/arm64/board/msm8x53-som/device-tree.dtb
new file mode 100644
index 0000000..32c65a4
--- /dev/null
+++ b/kernel/target/arm64/board/msm8x53-som/device-tree.dtb
Binary files differ
diff --git a/kernel/target/arm64/board/msm8x53-som/device-tree.dts b/kernel/target/arm64/board/msm8x53-som/device-tree.dts
new file mode 100644
index 0000000..4475470
--- /dev/null
+++ b/kernel/target/arm64/board/msm8x53-som/device-tree.dts
@@ -0,0 +1,19 @@
+/dts-v1/;
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ 8953 Lite";
+ qcom,msm-id = <304 0x0>;
+ qcom,pmic-id = <0x10016 0x20011 0x0 0x0>;
+ qcom,board-id = <0x01010020 0>;
+
+ chosen {
+ // need a dummy bootargs for bootloader to append to
+ bootargs = "";
+ };
+
+ memory {
+ device_type = "memory";
+ };
+};
+
+// [730] Best match DTB tags 304/01010020/0x00000001/0/10016/20011/0/0/a12f1f36/3c2e4
diff --git a/kernel/target/arm64/board/msm8x53-som/package-image.sh b/kernel/target/arm64/board/msm8x53-som/package-image.sh
new file mode 100755
index 0000000..f1384ae
--- /dev/null
+++ b/kernel/target/arm64/board/msm8x53-som/package-image.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+# Copyright 2018 The Fuchsia Authors
+#
+# Use of this source code is governed by a MIT-style
+# license that can be found in the LICENSE file or at
+# https://opensource.org/licenses/MIT
+
+set -eo pipefail
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+ZIRCON_DIR=${DIR}/../../../../..
+SCRIPTS_DIR=${ZIRCON_DIR}/scripts
+
+${SCRIPTS_DIR}/package-image.sh -a -b msm8x53-som \
+ -d $ZIRCON_DIR/kernel/target/arm64/board/msm8x53-som/device-tree.dtb -D append \
+ -g -m -M 0x00000000 $@
diff --git a/kernel/target/arm64/board/msm8x53-som/partition-table.img b/kernel/target/arm64/board/msm8x53-som/partition-table.img
new file mode 100644
index 0000000..7760d95
--- /dev/null
+++ b/kernel/target/arm64/board/msm8x53-som/partition-table.img
Binary files differ
diff --git a/kernel/target/arm64/board/msm8x53-som/rules.mk b/kernel/target/arm64/board/msm8x53-som/rules.mk
new file mode 100644
index 0000000..8609d29
--- /dev/null
+++ b/kernel/target/arm64/board/msm8x53-som/rules.mk
@@ -0,0 +1,9 @@
+# Copyright 2018 The Fuchsia Authors
+#
+# Use of this source code is governed by a MIT-style
+# license that can be found in the LICENSE file or at
+# https://opensource.org/licenses/MIT
+
+PLATFORM_BOARD_NAME := msm8x53-som
+
+include kernel/target/arm64/boot-shim/rules.mk
diff --git a/kernel/target/arm64/board/msm8x53-som/update-device-tree.sh b/kernel/target/arm64/board/msm8x53-som/update-device-tree.sh
new file mode 100755
index 0000000..050cd90
--- /dev/null
+++ b/kernel/target/arm64/board/msm8x53-som/update-device-tree.sh
@@ -0,0 +1 @@
+dtc -I dts -o device-tree.dtb -O dtb device-tree.dts
diff --git a/kernel/target/arm64/boot-shim/msm8x53-som-uart.c b/kernel/target/arm64/boot-shim/msm8x53-som-uart.c
new file mode 100644
index 0000000..c80dfe8
--- /dev/null
+++ b/kernel/target/arm64/boot-shim/msm8x53-som-uart.c
@@ -0,0 +1,37 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <zircon/compiler.h>
+#include <stdint.h>
+#include "debug.h"
+
+#define UART_DM_N0_CHARS_FOR_TX 0x0040
+#define UART_DM_CR_CMD_RESET_TX_READY (3 << 8)
+
+#define UART_DM_SR 0x00A4
+#define UART_DM_SR_TXRDY (1 << 2)
+#define UART_DM_SR_TXEMT (1 << 3)
+
+#define UART_DM_TF 0x0100
+
+#define UARTREG(reg) (*(volatile uint32_t*)(0x078af000 + (reg)))
+
+void uart_pputc(char c) {
+ while (!(UARTREG(UART_DM_SR) & UART_DM_SR_TXEMT)) {
+ ;
+ }
+ UARTREG(UART_DM_N0_CHARS_FOR_TX) = UART_DM_CR_CMD_RESET_TX_READY;
+ UARTREG(UART_DM_N0_CHARS_FOR_TX) = 1;
+ __UNUSED uint32_t foo = UARTREG(UART_DM_N0_CHARS_FOR_TX);
+
+ // wait for TX ready
+ while (!(UARTREG(UART_DM_SR) & UART_DM_SR_TXRDY))
+ ;
+
+ *((volatile uint32_t*)(0x078af100)) = c;
+
+ // wait for TX ready
+ while (!(UARTREG(UART_DM_SR) & UART_DM_SR_TXRDY))
+ ;
+}
diff --git a/scripts/flash-msm8x53-som b/scripts/flash-msm8x53-som
new file mode 100755
index 0000000..c605a9d
--- /dev/null
+++ b/scripts/flash-msm8x53-som
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+# Copyright 2018 The Fuchsia Authors
+#
+# Use of this source code is governed by a MIT-style
+# license that can be found in the LICENSE file or at
+# https://opensource.org/licenses/MIT
+
+set -eo pipefail
+
+SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+ZIRCON_DIR=${SCRIPTS_DIR}/..
+
+${ZIRCON_DIR}/kernel/target/arm64/board/msm8x53-som/package-image.sh -B ${ZIRCON_DIR}/build-arm64
+
+${SCRIPTS_DIR}/flash-avb -b msm8x53-som
diff --git a/system/public/zircon/boot/driver-config.h b/system/public/zircon/boot/driver-config.h
index 4913ae1..d017f20 100644
--- a/system/public/zircon/boot/driver-config.h
+++ b/system/public/zircon/boot/driver-config.h
@@ -18,6 +18,7 @@
#define KDRV_MT8167_UART 0x5538544D // 'MT8U'
#define KDRV_HISILICON_POWER 0x4F505348 // 'HSPO'
#define KDRV_AMLOGIC_HDCP 0x484C4D41 // 'AMLH'
+#define KDRV_MSM_UART 0x554D534D // 'MSMU'
// kernel driver struct that can be used for simple drivers
// used by KDRV_PL011_UART, KDRV_AMLOGIC_UART and KDRV_NXP_IMX_UART
diff --git a/system/ulib/ddk/include/ddk/platform-defs.h b/system/ulib/ddk/include/ddk/platform-defs.h
index f2b401f..914a3d1 100644
--- a/system/ulib/ddk/include/ddk/platform-defs.h
+++ b/system/ulib/ddk/include/ddk/platform-defs.h
@@ -179,4 +179,8 @@
#define PDEV_DID_TEST_CHILD_3 4
#define PDEV_DID_TEST_GPIO 5
+// Qualcomm
+#define PDEV_VID_QUALCOMM 18
+#define PDEV_PID_QUALCOMM_MSM8X53 1
+
__END_CDECLS;