summaryrefslogtreecommitdiff
path: root/chip/ish/uart.c
diff options
context:
space:
mode:
authorJaiber John <jaiber.j.john@intel.com>2016-03-31 23:49:53 +0530
committerchrome-bot <chrome-bot@chromium.org>2016-11-04 18:31:29 -0700
commitd7b938f857755a6a9a7ffbe9f281a14821675a9f (patch)
tree829973af641af0124b847871248e7a9b4027456a /chip/ish/uart.c
parentcbae8f9b321f33734a34cb85c82636bbfa7663ee (diff)
downloadchrome-ec-d7b938f857755a6a9a7ffbe9f281a14821675a9f.tar.gz
ish: Add support for ISH chip
This patch adds the initial support for ISH chip to enable the EC firmware to boot on Intel Integrated Sensor Hub (ISH). The following are enabled: 1. Inter-Processor Communication (IPC) driver that enables the ISH to communicate with the host Operating system via shared registers. 2. High Precision Event Timer (HPET) driver that provides configurable timers for the FW to use in task scheduling. 3. I2C bus driver for accessing sensors. 4. UART console driver with TX support only. BUG=chrome-os-partner:51851 BRANCH=None TEST=`make buildall -j` Change-Id: I15d4c201b799cfa79bed220ee573b75f5cd7b1f7 Signed-off-by: Jaiber John <jaiber.j.john@intel.com> Signed-off-by: Alex Brill <alexander.brill@intel.com> Signed-off-by: Gomathi Kumar <gomathi.kumar@intel.com> Reviewed-on: https://chromium-review.googlesource.com/336710 Commit-Ready: Raj Mojumder <raj.mojumder@intel.com> Tested-by: Jaiber J John <jaiber.j.john@intel.com> Tested-by: Raj Mojumder <raj.mojumder@intel.com> Reviewed-by: Jaiber J John <jaiber.j.john@intel.com> Reviewed-by: Raj Mojumder <raj.mojumder@intel.com> Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Diffstat (limited to 'chip/ish/uart.c')
-rw-r--r--chip/ish/uart.c243
1 files changed, 243 insertions, 0 deletions
diff --git a/chip/ish/uart.c b/chip/ish/uart.c
new file mode 100644
index 0000000000..bb12624bcf
--- /dev/null
+++ b/chip/ish/uart.c
@@ -0,0 +1,243 @@
+/* Copyright (c) 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* UART module for ISH */
+#include "common.h"
+#include "console.h"
+#include "uart_defs.h"
+#include "atomic.h"
+#include "task.h"
+#include "registers.h"
+#include "uart.h"
+#include "uart_defs.h"
+#include "interrupts.h"
+
+#define CPUTS(outstr) cputs(CC_LPC, outstr)
+#define CPRINTS(format, args...) cprints(CC_LPC, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_LPC, format, ## args)
+
+static const uint32_t baud_conf[][BAUD_TABLE_MAX] = {
+ {B9600, 9600},
+ {B57600, 57600},
+ {B115200, 115200},
+ {B921600, 921600},
+ {B2000000, 2000000},
+ {B3000000, 3000000},
+ {B3250000, 3250000},
+ {B3500000, 3500000},
+ {B4000000, 4000000},
+ {B19200, 19200},
+};
+
+static struct uart_ctx uart_ctx[UART_DEVICES] = {
+ {
+ .id = 0,
+ .base = UART0_BASE,
+ .input_freq = UART_ISH_INPUT_FREQ,
+ .addr_interval = UART_ISH_ADDR_INTERVAL,
+ .uart_state = UART_STATE_CG,
+ },
+ {
+ .id = 1,
+ .base = UART1_BASE,
+ .input_freq = UART_ISH_INPUT_FREQ,
+ .addr_interval = UART_ISH_ADDR_INTERVAL,
+ .uart_state = UART_STATE_CG,
+ }
+};
+
+static int init_done;
+
+int uart_init_done(void)
+{
+ return init_done;
+}
+
+void uart_tx_start(void)
+{
+ /* TBD for RX and interrupt enabled TX */
+}
+
+void uart_tx_stop(void)
+{
+ /* TBD for RX and interrupt enabled TX */
+}
+
+void uart_tx_flush(void)
+{
+ /* TBD for RX and interrupt enabled TX */
+}
+
+int uart_tx_ready(void)
+{
+ return 1;
+}
+
+int uart_rx_available(void)
+{
+ /* No RX FIFO */
+ return 0;
+}
+
+void uart_write_char(char c)
+{
+ int id = 1; /* In ISH, UART1 is assigned for console outpu */
+
+ /* Wait till reciever is ready */
+ while ((REG8(LSR(id)) & LSR_TEMT) == 0)
+ ;
+
+ REG8(THR(id)) = c;
+}
+
+static int uart_return_baud_rate_by_id(int baud_rate_id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(baud_conf); i++) {
+ if (baud_conf[i][BAUD_IDX] == baud_rate_id)
+ return baud_conf[i][BAUD_SPEED];
+ }
+
+ return -1;
+}
+
+static void uart_hw_init(enum UART_PORT id)
+{
+ uint32_t divisor; /* baud rate divisor */
+ uint8_t mcr = 0;
+ uint8_t fcr = 0;
+ struct uart_ctx *ctx = &uart_ctx[id];
+
+ interrupt_disable();
+
+ /* Calculate baud rate divisor */
+ divisor = (ctx->input_freq / ctx->baud_rate) >> 4;
+
+ REG32(MUL(ctx->id)) = (divisor * ctx->baud_rate);
+ REG32(DIV(ctx->id)) = (ctx->input_freq / 16);
+ REG32(PS(ctx->id)) = 16;
+
+ /* Set the DLAB to access the baud rate divisor registers */
+ REG8(LCR(ctx->id)) = LCR_DLAB;
+ REG8(DLL(ctx->id)) = (divisor & 0xff);
+ REG8(DLH(ctx->id)) = ((divisor >> 8) & 0xff);
+
+ /* 8 data bits, 1 stop bit, no parity, clear DLAB */
+ REG8(LCR(ctx->id)) = LCR_8BIT_CHR;
+
+ if (ctx->client_flags & UART_CONFIG_HW_FLOW_CONTROL)
+ mcr = MCR_AUTO_FLOW_EN;
+
+ mcr |= MCR_INTR_ENABLE; /* needs to be set regardless of flow control */
+
+ mcr |= (MCR_RTS | MCR_DTR);
+ REG8(MCR(ctx->id)) = mcr;
+
+ fcr = FCR_FIFO_SIZE_64 | FCR_ITL_FIFO_64_BYTES_1;
+
+ /* configure FIFOs */
+ REG8(FCR(ctx->id)) = (fcr | FCR_FIFO_ENABLE
+ | FCR_RESET_RX | FCR_RESET_TX);
+
+ /* enable UART unit */
+ REG32(ABR(ctx->id)) = ABR_UUE;
+
+ /* clear the port */
+ REG8(RBR(ctx->id));
+ REG8(IER(ctx->id)) = 0x00;
+
+ interrupt_enable();
+}
+
+static void uart_stop_hw(enum UART_PORT id)
+{
+ int i;
+ uint32_t fifo_len;
+
+ /* Manually clearing the fifo from possible noise.
+ * Entering D0i3 when fifo is not cleared may result in a hang.
+ */
+ fifo_len = (REG32(FOR(id)) & FOR_OCCUPANCY_MASK) >> FOR_OCCUPANCY_OFFS;
+
+ for (i = 0; i < fifo_len; i++)
+ (void)REG8(RBR(id));
+
+ /* No interrupts are enabled */
+ REG8(IER(id)) = 0;
+ REG8(MCR(id)) = 0;
+
+ /* Clear and disable FIFOs */
+ REG8(FCR(id)) = (FCR_RESET_RX | FCR_RESET_TX);
+
+ /* Disable uart unit */
+ REG32(ABR(id)) = 0;
+}
+
+static int uart_client_init(enum UART_PORT id, uint32_t baud_rate_id, int flags)
+{
+
+ if ((uart_ctx[id].base == 0) || (id >= UART_DEVICES))
+ return UART_ERROR;
+
+ if (!bool_compare_and_swap_u32(&uart_ctx[id].is_open, 0, 1))
+ return UART_BUSY;
+
+ uart_ctx[id].baud_rate = uart_return_baud_rate_by_id(baud_rate_id);
+
+ if ((uart_ctx[id].baud_rate == -1) || (uart_ctx[id].baud_rate == 0))
+ uart_ctx[id].baud_rate = UART_DEFAULT_BAUD_RATE;
+
+ uart_ctx[id].client_flags = flags;
+
+ atomic_and(&uart_ctx[id].uart_state, ~UART_STATE_CG);
+ uart_hw_init(id);
+
+ return EC_SUCCESS;
+}
+
+static void uart_drv_init(void)
+{
+ int i;
+ uint32_t fifo_len;
+
+ /* Disable UART */
+ for (i = 0; i < UART_DEVICES; i++)
+ uart_stop_hw(i);
+
+ /* Enable HSU global interrupts (DMA/U0/U1) and set PMEN bit
+ * to allow PMU to clock gate ISH
+ */
+ REG32(HSU_BASE + HSU_REG_GIEN) = (GIEN_DMA_EN | GIEN_UART0_EN
+ | GIEN_UART1_EN | GIEN_PWR_MGMT);
+
+ /* There is a by design HW "bug" where all UARTs are enabled by default
+ * but they must be disbled to enter clock gating.
+ * UART0 and UART1 are disabled during their init - but we don't init
+ * UART2 so as a w/a we disable UART2 even though it isn't being used.
+ * we also clear UART 2 fifo, which may cause problem entrying TCG is
+ * not empty (we do the same for UART0 and 1 in "uart_stop_hw"
+ */
+
+ fifo_len = (REG32(UART2_BASE + UART_REG_FOR)
+ & FOR_OCCUPANCY_MASK) >> FOR_OCCUPANCY_OFFS;
+
+ for (i = 0; i < fifo_len; i++)
+ (void)REG8((UART2_BASE + UART_REG_RBR));
+
+ REG32(UART2_BASE + UART_REG_ABR) = 0;
+
+ task_enable_irq(ISH_UART0_IRQ);
+ task_enable_irq(ISH_UART1_IRQ);
+}
+
+void uart_init(void)
+{
+
+ uart_drv_init();
+
+ uart_client_init(UART_PORT_1, B115200, 0);
+ init_done = 1;
+}