mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-29 18:11:05 +00:00
Add ECST tool to modify the header used by npcx booter. Modified drivers: 1. i2c.c: Modify for i2c_port design. 2. i2c.c: Fixed bugs when mutil-tasks use the same i2c port and pull-up issue. 3. hwtimer.c: Fixed bug whcih event expired time is behide current timer. 4. lpc.c: Add intializing host settings after pltrst is deasserted. 5. uart.c/clock.c/register.h: Fixed bug which cannot enter deep-idle when gpio is any-edge trigger mode. 6. task.c: Add workaround method for hard fault issue. 7. keyboard_raw.c: Modified for support CONFIG_KEYBOARD_KSO_BASE 8. lpc.c: Modified for support CONFIG_KEYBOARD_IRQ_GPIO 9. lpc.c: fixed obe interrupt bug during 8042 initialization 10.Adjust path of flat files for new Makefile rules 11.Fixed build error on lpc.c without CONFIG_KEYBOARD_IRQ_GPIO BUG=chrome-os-partner:34346 TEST=make buildall -j; test nuvoton IC specific drivers BRANCH=none Change-Id: Icf9494174b245b4026e396be877d578f36b6f6a5 Signed-off-by: Ian Chao <mlchao@nuvoton.com> Reviewed-on: https://chromium-review.googlesource.com/284036 Reviewed-by: Shawn N <shawnn@chromium.org> Tested-by: Shawn N <shawnn@chromium.org> Commit-Queue: Shawn N <shawnn@chromium.org>
218 lines
4.7 KiB
C
218 lines
4.7 KiB
C
/* Copyright (c) 2014 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 Chrome EC */
|
|
|
|
#include "clock.h"
|
|
#include "common.h"
|
|
#include "console.h"
|
|
#include "gpio.h"
|
|
#include "lpc.h"
|
|
#include "registers.h"
|
|
#include "clock_chip.h"
|
|
#include "system.h"
|
|
#include "task.h"
|
|
#include "uart.h"
|
|
#include "util.h"
|
|
|
|
static int init_done;
|
|
|
|
int uart_init_done(void)
|
|
{
|
|
return init_done;
|
|
}
|
|
|
|
void uart_tx_start(void)
|
|
{
|
|
if (uart_is_enable_wakeup()) {
|
|
/* disable MIWU */
|
|
uart_enable_wakeup(0);
|
|
/* Set pin-mask for UART */
|
|
npcx_gpio2uart();
|
|
/* enable uart again from MIWU mode */
|
|
task_enable_irq(NPCX_IRQ_UART);
|
|
}
|
|
|
|
/* If interrupt is already enabled, nothing to do */
|
|
if (NPCX_UICTRL & 0x20)
|
|
return;
|
|
|
|
/* Do not allow deep sleep while transmit in progress */
|
|
disable_sleep(SLEEP_MASK_UART);
|
|
|
|
/*
|
|
* Re-enable the transmit interrupt, then forcibly trigger the
|
|
* interrupt. This works around a hardware problem with the
|
|
* UART where the FIFO only triggers the interrupt when its
|
|
* threshold is _crossed_, not just met.
|
|
*/
|
|
NPCX_UICTRL |= 0x20;
|
|
|
|
task_trigger_irq(NPCX_IRQ_UART);
|
|
}
|
|
|
|
void uart_tx_stop(void) /* Disable TX interrupt */
|
|
{
|
|
NPCX_UICTRL &= ~0x20;
|
|
|
|
/* Re-allow deep sleep */
|
|
enable_sleep(SLEEP_MASK_UART);
|
|
}
|
|
|
|
void uart_tx_flush(void)
|
|
{
|
|
/* Wait for transmit FIFO empty */
|
|
while (!(NPCX_UICTRL & 0x01))
|
|
;
|
|
}
|
|
|
|
int uart_tx_ready(void)
|
|
{
|
|
return NPCX_UICTRL & 0x01; /*if TX FIFO is empty return 1*/
|
|
}
|
|
|
|
int uart_tx_in_progress(void)
|
|
{
|
|
/* Transmit is in progress if the TX busy bit is set. */
|
|
return NPCX_USTAT & 0x40; /*BUSY bit , if busy return 1*/
|
|
}
|
|
|
|
int uart_rx_available(void)
|
|
{
|
|
uint8_t ctrl = NPCX_UICTRL;
|
|
#ifdef CONFIG_LOW_POWER_IDLE
|
|
/*
|
|
* Activity seen on UART RX pin while UART was disabled for deep sleep.
|
|
* The console won't see that character because the UART is disabled,
|
|
* so we need to inform the clock module of UART activity ourselves.
|
|
*/
|
|
if (ctrl & 0x02)
|
|
clock_refresh_console_in_use();
|
|
#endif
|
|
return ctrl & 0x02; /* If RX FIFO is empty return '0'*/
|
|
}
|
|
|
|
void uart_write_char(char c)
|
|
{
|
|
/* Wait for space in transmit FIFO. */
|
|
while (!uart_tx_ready())
|
|
;
|
|
|
|
NPCX_UTBUF = c;
|
|
#ifdef CONFIG_LOW_POWER_IDLE
|
|
clock_refresh_console_in_use();
|
|
#endif
|
|
}
|
|
|
|
int uart_read_char(void)
|
|
{
|
|
return NPCX_URBUF;
|
|
}
|
|
|
|
static void uart_clear_rx_fifo(int channel)
|
|
{
|
|
int scratch __attribute__ ((unused));
|
|
if (channel == 0) { /* suppose '0' is EC UART*/
|
|
/*if '1' that mean have a RX data on the FIFO register*/
|
|
while ((NPCX_UICTRL & 0x02))
|
|
scratch = NPCX_URBUF;
|
|
}
|
|
}
|
|
|
|
void uart_disable_interrupt(void)
|
|
{
|
|
task_disable_irq(NPCX_IRQ_UART);
|
|
}
|
|
|
|
void uart_enable_interrupt(void)
|
|
{
|
|
task_enable_irq(NPCX_IRQ_UART);
|
|
}
|
|
|
|
/**
|
|
* Interrupt handler for UART0
|
|
*/
|
|
void uart_ec_interrupt(void)
|
|
{
|
|
/* Read input FIFO until empty, then fill output FIFO */
|
|
uart_process_input();
|
|
uart_process_output();
|
|
}
|
|
DECLARE_IRQ(NPCX_IRQ_UART, uart_ec_interrupt, 1);
|
|
|
|
|
|
static void uart_config(void)
|
|
{
|
|
uint32_t div, opt_dev, min_deviation, clk, calc_baudrate, deviation;
|
|
uint8_t prescalar, opt_prescalar, i;
|
|
|
|
/* Configure pins from GPIOs to CR_UART */
|
|
gpio_config_module(MODULE_UART, 1);
|
|
/* Enable MIWU IRQ of UART*/
|
|
#if NPCX_UART_MODULE2
|
|
task_enable_irq(NPCX_IRQ_WKINTG_1);
|
|
#else
|
|
task_enable_irq(NPCX_IRQ_WKINTB_1);
|
|
|
|
#endif
|
|
|
|
/* Calculated UART baudrate , clock source from APB2 */
|
|
opt_prescalar = opt_dev = 0;
|
|
prescalar = 10;
|
|
min_deviation = 0xFFFFFFFF;
|
|
clk = clock_get_apb2_freq();
|
|
for (i = 1; i < 31; i++) {
|
|
div = (clk * 10) / (16 * CONFIG_UART_BAUD_RATE * prescalar);
|
|
if (div != 0) {
|
|
calc_baudrate = (clk * 10) / (16 * div * prescalar);
|
|
deviation = (calc_baudrate > CONFIG_UART_BAUD_RATE) ?
|
|
(calc_baudrate - CONFIG_UART_BAUD_RATE) :
|
|
(CONFIG_UART_BAUD_RATE - calc_baudrate);
|
|
if (deviation < min_deviation) {
|
|
min_deviation = deviation;
|
|
opt_prescalar = i;
|
|
opt_dev = div;
|
|
}
|
|
}
|
|
prescalar += 5;
|
|
}
|
|
opt_dev--;
|
|
NPCX_UPSR = ((opt_prescalar<<3) & 0xF8) | ((opt_dev >> 8) & 0x7);
|
|
NPCX_UBAUD = (uint8_t)opt_dev;
|
|
/*
|
|
* 8-N-1, FIFO enabled. Must be done after setting
|
|
* the divisor for the new divisor to take effect.
|
|
*/
|
|
NPCX_UFRS = 0x00;
|
|
NPCX_UICTRL = 0x40; /* receive int enable only */
|
|
}
|
|
|
|
void uart_init(void)
|
|
{
|
|
uint32_t mask = 0;
|
|
|
|
/*
|
|
* Enable UART0 in run, sleep, and deep sleep modes. Enable the Host
|
|
* UART in run and sleep modes.
|
|
*/
|
|
mask = 0x10; /* bit 4 */
|
|
clock_enable_peripheral(CGC_OFFSET_UART, mask, CGC_MODE_ALL);
|
|
|
|
/* Set pin-mask for UART */
|
|
npcx_gpio2uart();
|
|
|
|
/* Configure UARTs (identically) */
|
|
uart_config();
|
|
|
|
/*
|
|
* Enable interrupts for UART0 only. Host UART will have to wait
|
|
* until the LPC bus is initialized.
|
|
*/
|
|
uart_clear_rx_fifo(0);
|
|
task_enable_irq(NPCX_IRQ_UART);
|
|
|
|
init_done = 1;
|
|
}
|