diff --git a/arch/arm/dts/tegra20-paz00.dts b/arch/arm/dts/tegra20-paz00.dts index 780203c..2df5446 100644 --- a/arch/arm/dts/tegra20-paz00.dts +++ b/arch/arm/dts/tegra20-paz00.dts @@ -88,4 +88,12 @@ nvidia,panel-vdd-gpios = <&gpio 4 0>; /* PA4 */ nvidia,panel-timings = <400 4 203 17 15>; }; + + nvec { + compatible = "nvidia,tegra20-nvec"; + reg = <0x7000c500 0x100>; + clock-frequency = <80000>; + request-gpios = <&gpio 170 0>; /* gpio PV2 */ + slave-addr = <138>; + }; }; diff --git a/arch/arm/include/asm/arch-tegra/tegra_nvec.h b/arch/arm/include/asm/arch-tegra/tegra_nvec.h new file mode 100644 index 0000000..1c30028 --- /dev/null +++ b/arch/arm/include/asm/arch-tegra/tegra_nvec.h @@ -0,0 +1,117 @@ +/* + * (C) Copyright 2013 + * Andrey Danin + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _TEGRA_NVEC_H_ +#define _TEGRA_NVEC_H_ + +#define I2C_CNFG 0x00 +#define I2C_CNFG_PACKET_MODE_EN (1<<10) +#define I2C_CNFG_NEW_MASTER_SFM (1<<11) +#define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12 + +#define I2C_SL_CNFG 0x20 +#define I2C_SL_NEWSL (1<<2) +#define I2C_SL_NACK (1<<1) +#define I2C_SL_RESP (1<<0) +#define I2C_SL_IRQ (1<<3) +#define END_TRANS (1<<4) +#define RCVD (1<<2) +#define RNW (1<<1) + +#define I2C_SL_RCVD 0x24 +#define I2C_SL_STATUS 0x28 +#define I2C_SL_ADDR1 0x2c +#define I2C_SL_ADDR2 0x30 +#define I2C_SL_DELAY_COUNT 0x3c + + +enum nvec_msg_type { + NVEC_KEYBOARD = 0, + NVEC_SYS = 1, + NVEC_BAT, + NVEC_GPIO, + NVEC_SLEEP, + NVEC_KBD, + NVEC_PS2, + NVEC_CNTL, + NVEC_OEM0 = 0x0d, + NVEC_KB_EVT = 0x80, + NVEC_PS2_EVT, +}; + +enum nvec_event_size { + NVEC_2BYTES, + NVEC_3BYTES, + NVEC_VAR_SIZE, +}; + +enum sys_subcmds { + SYS_GET_STATUS, + SYS_CNFG_EVENT_REPORTING, + SYS_ACK_STATUS, + SYS_CNFG_WAKE = 0xfd, +}; + +enum kbd_subcmds { + CNFG_WAKE = 3, + CNFG_WAKE_KEY_REPORTING, + SET_LEDS = 0xed, + ENABLE_KBD = 0xf4, + DISABLE_KBD, +}; + +enum cntl_subcmds { + CNTL_RESET_EC = 0x00, + CNTL_SELF_TEST = 0x01, + CNTL_NOOP = 0x02, + CNTL_GET_EC_SPEC_VER = 0x10, + CNTL_GET_FIRMWARE_VERSION = 0x15, +}; + +enum nvec_sleep_subcmds { + GLOBAL_EVENTS, + AP_PWR_DOWN, + AP_SUSPEND, +}; + +#define MOUSE_SEND_CMD 0x01 +#define MOUSE_RESET 0xff + + +int board_nvec_init(void); + +int nvec_msg_is_event(const unsigned char *msg); +int nvec_msg_event_type(const unsigned char *msg); + +/** + * Send request and read response. If write or read failed + * operation will be repeated NVEC_ATTEMPTS_MAX times. + * + * @param buf request data + * @param size request data size + * @return 0 if ok, -1 on error + */ +int nvec_do_request(char *buf, int size); + + +#endif /* _TEGRA_NVEC_H_ */ diff --git a/arch/arm/include/asm/arch-tegra/tegra_nvec_events.h b/arch/arm/include/asm/arch-tegra/tegra_nvec_events.h new file mode 100644 index 0000000..7d65921 --- /dev/null +++ b/arch/arm/include/asm/arch-tegra/tegra_nvec_events.h @@ -0,0 +1,31 @@ +/* + * (C) Copyright 2013 + * Andrey Danin + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _TEGRA_NVEC_EVENTS_H_ +#define _TEGRA_NVEC_EVENTS_H_ + + +int nvec_read_events(void); + + +#endif /* _TEGRA_NVEC_EVENTS_H_ */ diff --git a/arch/arm/include/asm/arch-tegra/tegra_nvec_keyboard.h b/arch/arm/include/asm/arch-tegra/tegra_nvec_keyboard.h new file mode 100644 index 0000000..b25a1d8 --- /dev/null +++ b/arch/arm/include/asm/arch-tegra/tegra_nvec_keyboard.h @@ -0,0 +1,36 @@ +/* + * (C) Copyright 2013 + * Andrey Danin + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _TEGRA_NVEC_KEYBOARD_H_ +#define _TEGRA_NVEC_KEYBOARD_H_ + + +#define NVEC_KEYS_QUEUE_SIZE 256 + +void nvec_enable_kbd_events(void); +void nvec_process_keyboard_msg(const unsigned char *msg); +int nvec_pop_key(void); +int nvec_have_keys(void); + + +#endif /* _TEGRA_NVEC_KEYBOARD_H_ */ diff --git a/arch/arm/include/asm/arch-tegra/tegra_nvec_keytable.h b/arch/arm/include/asm/arch-tegra/tegra_nvec_keytable.h new file mode 100644 index 0000000..8fbf96c --- /dev/null +++ b/arch/arm/include/asm/arch-tegra/tegra_nvec_keytable.h @@ -0,0 +1,313 @@ +/* + * Keyboard class input driver for keyboards connected to an NvEc compliant + * embedded controller + * + * Copyright (c) 2009, NVIDIA Corporation. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _TEGRA_NVEC_KEYTABLE_H_ +#define _TEGRA_NVEC_KEYTABLE_H_ + +#include + + +static unsigned short code_tab_102us[] = { + /* 0x00 */ + KEY_GRAVE, + KEY_ESC, + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_0, + KEY_MINUS, + KEY_EQUAL, + KEY_BACKSPACE, + KEY_TAB, + /* 0x10 */ + KEY_Q, + KEY_W, + KEY_E, + KEY_R, + KEY_T, + KEY_Y, + KEY_U, + KEY_I, + KEY_O, + KEY_P, + KEY_LEFTBRACE, + KEY_RIGHTBRACE, + KEY_ENTER, + KEY_LEFTCTRL, + KEY_A, + KEY_S, + /* 0x20 */ + KEY_D, + KEY_F, + KEY_G, + KEY_H, + KEY_J, + KEY_K, + KEY_L, + KEY_SEMICOLON, + KEY_APOSTROPHE, + KEY_GRAVE, + KEY_LEFTSHIFT, + KEY_BACKSLASH, + KEY_Z, + KEY_X, + KEY_C, + KEY_V, + /* 0x30 */ + KEY_B, + KEY_N, + KEY_M, + KEY_COMMA, + KEY_DOT, + KEY_SLASH, + KEY_RIGHTSHIFT, + KEY_KPASTERISK, + KEY_LEFTALT, + KEY_SPACE, + KEY_CAPSLOCK, + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + /* 0x40 */ + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_FN, + /* VK_SCROLL */ + 0, + KEY_KP7, + KEY_KP8, + KEY_KP9, + KEY_KPMINUS, + KEY_KP4, + KEY_KP5, + KEY_KP6, + KEY_KPPLUS, + KEY_KP1, + /* 0x50 */ + KEY_KP2, + KEY_KP3, + KEY_KP0, + KEY_KPDOT, + /* VK_SNAPSHOT */ + 0, /* KEY_MENU, */ + KEY_POWER, + /* VK_OEM_102 */ + KEY_102ND, + KEY_F11, + KEY_F12, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0x60 */ + 0, + 0, + 0, + 0, /* KEY_SEARCH, */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0x70 */ + 0, + 0, + 0, + KEY_KP5, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + KEY_KP9, +}; + +static unsigned short extcode_tab_us102[] = { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0x10 */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* VK_MEDIA_NEXT_TRACK */ + 0, + 0, + 0, + /* VK_RETURN */ + 0, + KEY_RIGHTCTRL, + 0, + 0, + /* 0x20 */ + KEY_MUTE, + /* VK_LAUNCH_APP1 */ + 0, + /* VK_MEDIA_PLAY_PAUSE */ + 0, + 0, + /* VK_MEDIA_STOP */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0x30 */ + KEY_VOLUMEUP, + 0, + /* VK_BROWSER_HOME */ + 0, + 0, + 0, + /* VK_DIVIDE */ + KEY_KPSLASH, + 0, + /* VK_SNAPSHOT */ + KEY_SYSRQ, + /* VK_RMENU */ + KEY_RIGHTALT, + /* VK_OEM_NV_BACKLIGHT_UP */ + 0, + /* VK_OEM_NV_BACKLIGHT_DN */ + 0, + /* VK_OEM_NV_BACKLIGHT_AUTOTOGGLE */ + 0, + /* VK_OEM_NV_POWER_INFO */ + 0, + /* VK_OEM_NV_WIFI_TOGGLE */ + 0, + /* VK_OEM_NV_DISPLAY_SELECT */ + 0, + /* VK_OEM_NV_AIRPLANE_TOGGLE */ + 0, + /* 0x40 */ + 0, + KEY_LEFT, + 0, + 0, + 0, + 0, + 0, /* KEY_CANCEL, */ + KEY_HOME, + KEY_UP, + KEY_PAGEUP, + 0, + KEY_LEFT, + 0, + KEY_RIGHT, + 0, + KEY_END, + /* 0x50 */ + KEY_DOWN, + KEY_PAGEDOWN, + KEY_INSERT, + KEY_DELETE, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + KEY_LEFTMETA, + 0, + KEY_ESC, + KEY_KPMINUS, + 0, + 0, + 0, + 0, + 0, + 0, + /* VK_BROWSER_SEARCH */ + 0, + /* VK_BROWSER_FAVORITES */ + 0, + /* VK_BROWSER_REFRESH */ + 0, + /* VK_BROWSER_STOP */ + 0, + /* VK_BROWSER_FORWARD */ + 0, + /* VK_BROWSER_BACK */ + 0, + /* VK_LAUNCH_APP2 */ + 0, + /* VK_LAUNCH_MAIL */ + 0, + /* VK_LAUNCH_MEDIA_SELECT */ + 0, +}; + +static unsigned short *code_tabs[] = { code_tab_102us, extcode_tab_us102 }; + +#endif /* _TEGRA_NVEC_KEYTABLE_H_ */ diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c index d01abce..806d1bd 100644 --- a/board/nvidia/common/board.c +++ b/board/nvidia/common/board.c @@ -37,6 +37,9 @@ #include #include #endif +#ifdef CONFIG_TEGRA_NVEC +#include +#endif #include #include #include "emc.h" @@ -197,10 +200,19 @@ int board_early_init_f(void) int board_late_init(void) { + __maybe_unused int err; + #ifdef CONFIG_LCD /* Make sure we finish initing the LCD */ tegra_lcd_check_next_stage(gd->fdt_blob, 1); #endif + +#ifdef CONFIG_TEGRA_NVEC + err = board_nvec_init(); + if (err) + debug("NVEC controller init failed: %d\n", err); +#endif + return 0; } diff --git a/common/Makefile b/common/Makefile index de5cce8..aeeb626 100644 --- a/common/Makefile +++ b/common/Makefile @@ -200,6 +200,7 @@ obj-$(CONFIG_CMD_ZFS) += cmd_zfs.o # others obj-$(CONFIG_BOOTSTAGE) += bootstage.o obj-$(CONFIG_CONSOLE_MUX) += iomux.o +obj-$(CONFIG_ANSI_CONSOLE) += ansi_console.o obj-y += flash.o obj-$(CONFIG_CMD_KGDB) += kgdb.o kgdb_stubs.o obj-$(CONFIG_I2C_EDID) += edid.o diff --git a/common/ansi_console.c b/common/ansi_console.c new file mode 100644 index 0000000..f68e9c5 --- /dev/null +++ b/common/ansi_console.c @@ -0,0 +1,210 @@ +#include + + +void ansi_putc(struct ansi_console_t* console, const char c) +{ + int i; + + if (c == 27) { + for (i = 0; i < console->ansi_buf_size; ++i) + console->putc(console->ansi_buf[i]); + console->ansi_buf[0] = 27; + console->ansi_buf_size = 1; + return; + } + + if (console->ansi_buf_size > 0) { + /* + * 0 - ESC + * 1 - [ + * 2 - num1 + * 3 - .. + * 4 - ; + * 5 - num2 + * 6 - .. + * - cchar + */ + int next = 0; + + int flush = 0; + int fail = 0; + + int num1 = 0; + int num2 = 0; + int cchar = 0; + + console->ansi_buf[console->ansi_buf_size++] = c; + + if (console->ansi_buf_size >= sizeof(console->ansi_buf)) + fail = 1; + + for (i = 0; i < console->ansi_buf_size; ++i) { + if (fail) + break; + + switch (next) { + case 0: + if (console->ansi_buf[i] == 27) + next = 1; + else + fail = 1; + break; + + case 1: + if (console->ansi_buf[i] == '[') + next = 2; + else + fail = 1; + break; + + case 2: + if (console->ansi_buf[i] >= '0' && console->ansi_buf[i] <= '9') { + num1 = console->ansi_buf[i]-'0'; + next = 3; + } else if (console->ansi_buf[i] != '?') { + --i; + num1 = 1; + next = 4; + } + break; + + case 3: + if (console->ansi_buf[i] >= '0' && console->ansi_buf[i] <= '9') { + num1 *= 10; + num1 += console->ansi_buf[i]-'0'; + } else { + --i; + next = 4; + } + break; + + case 4: + if (console->ansi_buf[i] != ';') { + --i; + next = 7; + } else + next = 5; + break; + + case 5: + if (console->ansi_buf[i] >= '0' && console->ansi_buf[i] <= '9') { + num2 = console->ansi_buf[i]-'0'; + next = 6; + } else + fail = 1; + break; + + case 6: + if (console->ansi_buf[i] >= '0' && console->ansi_buf[i] <= '9') { + num2 *= 10; + num2 += console->ansi_buf[i]-'0'; + } else { + --i; + next = 7; + } + break; + + case 7: + if ((console->ansi_buf[i] >= 'A' && console->ansi_buf[i] <= 'H') + || console->ansi_buf[i] == 'J' + || console->ansi_buf[i] == 'K' + || console->ansi_buf[i] == 'h' + || console->ansi_buf[i] == 'l' + || console->ansi_buf[i] == 'm') { + cchar = console->ansi_buf[i]; + flush = 1; + } else + fail = 1; + break; + } + } + + if (fail) { + for (i = 0; i < console->ansi_buf_size; ++i) + console->putc(console->ansi_buf[i]); + console->ansi_buf_size = 0; + return; + } + + if (flush) { + if (!console->ansi_cursor_hidden && console->cursor_enable) + console->cursor_enable(0); + console->ansi_buf_size = 0; + switch (cchar) { + case 'A': + /* move cursor num1 rows up */ + console->cursor_up(num1); + break; + case 'B': + /* move cursor num1 rows down */ + console->cursor_down(num1); + break; + case 'C': + /* move cursor num1 columns forward */ + console->cursor_right(num1); + break; + case 'D': + /* move cursor num1 columns back */ + console->cursor_left(num1); + break; + case 'E': + /* move cursor num1 rows up at begin of row */ + console->previous_line(num1); + break; + case 'F': + /* move cursor num1 rows down at begin of row */ + console->new_line(num1); + break; + case 'G': + /* move cursor to column num1 */ + console->set_position(-1, num1-1); + break; + case 'H': + /* move cursor to row num1, column num2 */ + console->set_position(num1-1, num2-1); + break; + case 'J': + /* clear console and move cursor to 0, 0 */ + console->clear(); + console->set_position(0, 0); + break; + case 'K': + /* clear line */ + if (num1 == 0) + console->clear_line(*console->console_row, + *console->console_col, + -1); + else if (num1 == 1) + console->clear_line(*console->console_row, + 0, *console->console_col); + else + console->clear_line(*console->console_row, + 0, -1); + break; + case 'h': + console->ansi_cursor_hidden = 0; + break; + case 'l': + console->ansi_cursor_hidden = 1; + break; + case 'm': + if (num1 == 0) { /* reset swapped colors */ + if (console->ansi_colors_need_revert && console->swap_colors) { + console->swap_colors(); + console->ansi_colors_need_revert = 0; + } + } else if (num1 == 7) { /* once swap colors */ + if (!console->ansi_colors_need_revert && console->swap_colors) { + console->swap_colors(); + console->ansi_colors_need_revert = 1; + } + } + break; + } + if (!console->ansi_cursor_hidden && console->cursor_set) + console->cursor_set(); + } + } else { + console->putc(c); + } +} diff --git a/common/lcd.c b/common/lcd.c index 19b86b7..f708a79 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -25,6 +25,7 @@ #include #endif #include +#include #include #include #include @@ -108,6 +109,7 @@ DECLARE_GLOBAL_DATA_PTR; +void lcd_position_cursor_n(int col, int row); static void lcd_drawchars(ushort x, ushort y, uchar *str, int count); static inline void lcd_puts_xy(ushort x, ushort y, uchar *s); static inline void lcd_putc_xy(ushort x, ushort y, uchar c); @@ -119,6 +121,9 @@ static void *lcd_logo(void); static int lcd_getbgcolor(void); static void lcd_setfgcolor(int color); static void lcd_setbgcolor(int color); +#ifdef CONFIG_ANSI_CONSOLE +static void lcd_swap_colors(void); +#endif static int lcd_color_fg; static int lcd_color_bg; @@ -126,14 +131,24 @@ int lcd_line_length; char lcd_is_enabled = 0; +#ifdef CONFIG_ANSI_CONSOLE +static int console_col; +static int console_row; +#else static short console_col; static short console_row; +#endif static void *lcd_console_address; static void *lcd_base; /* Start of framebuffer memory */ static char lcd_flush_dcache; /* 1 to flush dcache after each lcd update */ +#ifdef CONFIG_ANSI_CONSOLE +struct ansi_console_t ansi_console; +#endif + + /************************************************************************/ /* Flush LCD activity to the caches */ @@ -167,9 +182,9 @@ void lcd_set_flush_dcache(int flush) /*----------------------------------------------------------------------*/ -static void console_scrollup(void) +static void console_scrollup_n(int n) { - const int rows = CONFIG_CONSOLE_SCROLL_LINES; + const int rows = n; /* Copy up rows ignoring those that will be overwritten */ memcpy(CONSOLE_ROW_FIRST, @@ -199,19 +214,85 @@ static inline void console_back(void) console_row * VIDEO_FONT_HEIGHT, ' '); } + /*----------------------------------------------------------------------*/ +static inline void console_newline_n(int n) +{ + console_col = 0; + + console_row += n; + /* Check if we need to scroll the terminal */ + if (console_row >= CONSOLE_ROWS) + console_scrollup_n(CONSOLE_ROWS - console_row + 1); + else + lcd_sync(); +} + static inline void console_newline(void) { + console_newline_n(1); +} + +/*----------------------------------------------------------------------*/ + +static inline void console_prevline_n(int n) +{ console_col = 0; + console_row -= n; /* Check if we need to scroll the terminal */ - if (++console_row >= CONSOLE_ROWS) - console_scrollup(); + if (console_row < 0) + console_scrollup_n(1 - console_row); else lcd_sync(); } +static inline void console_prevline(void) +{ + console_prevline_n(1); +} + +/*----------------------------------------------------------------------*/ + +static inline void console_cursor_up(int n) +{ + console_row -= n; + if (console_row < 0) + console_row = 0; +} + +static inline void console_cursor_down(int n) +{ + console_row += n; + if (console_row >= CONSOLE_ROWS) + console_row = CONSOLE_ROWS-1; +} + +static inline void console_cursor_left(int n) +{ + console_col -= n; + if (console_col < 0) + console_col = 0; +} + +static inline void console_cursor_right(int n) +{ + console_col += n; + if (console_col >= CONSOLE_COLS) + console_col = CONSOLE_COLS-1; +} + +/*----------------------------------------------------------------------*/ + +static inline void console_clear_line(int line, int begin, int end) +{ + short i = 0; + for (i = begin; i < end; ++i) + lcd_putc_xy(i * VIDEO_FONT_WIDTH, + line * VIDEO_FONT_HEIGHT, ' '); +} + /*----------------------------------------------------------------------*/ void lcd_putc(const char c) @@ -262,7 +343,11 @@ void lcd_puts(const char *s) } while (*s) +#ifdef CONFIG_ANSI_CONSOLE + ansi_putc(&ansi_console, *s++); +#else lcd_putc(*s++); +#endif lcd_sync(); } @@ -525,6 +610,28 @@ static int lcd_init(void *lcdbase) console_row = 1; /* leave 1 blank line below logo */ #endif +#ifdef CONFIG_ANSI_CONSOLE + memset(&ansi_console, 0, sizeof(ansi_console)); + ansi_console.putc = lcd_putc; +#if defined(CONFIG_CONSOLE_CURSOR) || defined(CONFIG_VIDEO_SW_CURSOR) + ansi_console.cursor_set = lcd_set_cursor; + ansi_console.cursor_enable = lcd_cursor; + /* TODO Add on/off */ +#endif + ansi_console.cursor_up = console_cursor_up; + ansi_console.cursor_down = console_cursor_down; + ansi_console.cursor_left = console_cursor_left; + ansi_console.cursor_right = console_cursor_right; + ansi_console.previous_line = console_prevline_n; + ansi_console.new_line = console_newline_n; + ansi_console.set_position = lcd_position_cursor_n; + ansi_console.clear_line = console_clear_line; + ansi_console.clear = lcd_clear; + ansi_console.swap_colors = lcd_swap_colors; + ansi_console.console_col = &console_col; + ansi_console.console_row = &console_row; +#endif /* CONFIG_CONSOLE_ANSI */ + return 0; } @@ -590,6 +697,17 @@ static int lcd_getbgcolor(void) return lcd_color_bg; } +/*----------------------------------------------------------------------*/ + +#ifdef CONFIG_ANSI_CONSOLE +static void lcd_swap_colors(void) +{ + int tmp = lcd_color_bg; + lcd_color_bg = lcd_color_fg; + lcd_color_fg = tmp; +} +#endif + /************************************************************************/ /* ** Chipset depending Bitmap / Logo stuff... */ /************************************************************************/ @@ -1141,6 +1259,11 @@ void lcd_position_cursor(unsigned col, unsigned row) console_row = min(row, CONSOLE_ROWS - 1); } +void lcd_position_cursor_n(int row, int col) +{ + lcd_position_cursor((unsigned)col, (unsigned)row); +} + int lcd_get_pixel_width(void) { return panel_info.vl_col; diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 96bd45d..f78083f 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -29,4 +29,5 @@ obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o +obj-$(CONFIG_TEGRA_NVEC) += tegra_nvec.o tegra_nvec_keyboard.o obj-$(CONFIG_SYS_I2C_ZYNQ) += zynq_i2c.o diff --git a/drivers/i2c/tegra_nvec.c b/drivers/i2c/tegra_nvec.c new file mode 100644 index 0000000..1589003 --- /dev/null +++ b/drivers/i2c/tegra_nvec.c @@ -0,0 +1,462 @@ +/* + * (C) Copyright 2013 + * Andrey Danin + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef CONFIG_TEGRA_NVEC +#error "You should enable CONFIG_TEGRA_NVEC" +#endif + +DECLARE_GLOBAL_DATA_PTR; + + +/* Nvec perfroms io interval is beteween 20 and 500 ms, +no response in 600 ms means error */ +enum { + NVEC_TIMEOUT_MIN = 20, + NVEC_TIMEOUT_MAX = 600, +}; +enum { + NVEC_WAIT_FOR_EC = 1, + NVEC_DONT_WAIT_FOR_EC = 0, + NVEC_ATTEMPTS_MAX = 10, +}; + +enum { + nvec_io_error = -1, + nvec_io_timeout, + nvec_io_read_ok, + nvec_io_write_ok, + nvec_io_not_ready, + nvec_io_retry, +}; + +enum { + NVST_BEGIN = 0, + NVST_CMD = 1, + NVST_SUBCMD = 2, + NVST_READ = 3, + NVST_WRITE_SIZE = 4, + NVST_WRITE = 5, +}; + +struct nvec_t { + int gpio; + int i2c_addr; + int i2c_clk; + void __iomem *base; + int state; + char rx_buf[34]; + int rx_pos; + char *tx_buf; + int tx_pos; + int tx_size; +} nvec_data; + +struct fdt_nvec_config { + int gpio; + int i2c_addr; + int i2c_clk; + fdt_addr_t base_addr; + struct fdt_gpio_state request_gpio; +}; + + +/* nvec commands */ +char noop[] = { NVEC_CNTL, CNTL_NOOP }; + + +int nvec_msg_is_event(const unsigned char *msg) +{ + return msg[0] >> 7; +} + + +int nvec_msg_event_type(const unsigned char *msg) +{ + return msg[0] & 0x0f; +} + + +/** + * Process incoming io message. + * If message is keyboard event then key code will + * be added to keys buffer. + * + * See: nvec_push_key, nvec_pop_key, nvec_have_key + * + * @param nvec nvec state struct + */ +void nvec_process_msg(struct nvec_t *nvec) +{ + const unsigned char *msg = (const unsigned char *)nvec->rx_buf; + int event_type; + + if (!nvec_msg_is_event(msg)) + return; + + event_type = nvec_msg_event_type(msg); + if (event_type == NVEC_KEYBOARD) + nvec_process_keyboard_msg(msg); +} + + +static inline int is_read(unsigned long status) +{ + return (status & RNW) == 0; +} + + +static inline int is_ready(unsigned long status) +{ + return status & I2C_SL_IRQ; +} + + +/** + * Perform complete io operation (read or write). + * NOTE: function will wait NVEC_TIMEOUT_MIN (20ms) + * before status check to avoid nvec hang. + * + * @param nvec nvec state struct + * @param wait_for_ec if 1(NVEC_WAIT_FOR_EC) operation + * timeout is NVEC_TIMEOUT_MAX (600ms), + * otherwise function will return if io + * is not ready. + * + * @return nvec_io_* code + */ +int nvec_do_io(struct nvec_t *nvec, int wait_for_ec) +{ + unsigned int poll_start_ms = 0; + unsigned long status; + unsigned int received = 0; + unsigned int to_send = 0; + unsigned int timeout_ms = NVEC_TIMEOUT_MAX; + int is_first_iteration = 1; + + poll_start_ms = get_timer(0); + mdelay(NVEC_TIMEOUT_MIN); + + while (1) { + status = readl(nvec->base + I2C_SL_STATUS); + if (!is_ready(status)) { + if (is_first_iteration && !wait_for_ec) + return nvec_io_not_ready; + + if (get_timer(poll_start_ms) > timeout_ms) + return nvec_io_timeout; + + is_first_iteration = 0; + udelay(100); + continue; + } + is_first_iteration = 0; + + if (is_read(status)) + received = readl(nvec->base + I2C_SL_RCVD); + + if (status == (I2C_SL_IRQ | RCVD)) { + nvec->state = NVST_BEGIN; + nvec->rx_pos = 0; + nvec->tx_pos = 0; + } + + switch (nvec->state) { + case NVST_BEGIN: + nvec->rx_pos = 0; + nvec->tx_pos = 0; + if (received != nvec->i2c_addr) { + error("NVEC io: unknown addr 0x%x\n", received); + return nvec_io_error; + } + nvec->state = NVST_CMD; + break; + + case NVST_CMD: + nvec->rx_buf[nvec->rx_pos++] = (char)received; + nvec->state = NVST_SUBCMD; + break; + + case NVST_SUBCMD: + if (status == (I2C_SL_IRQ | RNW | RCVD)) { + if (nvec->rx_buf[0] != 0x01) { + error("NVEC io: wrong read\n"); + nvec->state = NVST_BEGIN; + return nvec_io_error; + } + nvec->state = NVST_WRITE; + if (nvec->tx_buf == 0) { + debug("NVEC io: error, tx buffer is 0\n"); + nvec->tx_buf = noop; + nvec->tx_size = 2; + nvec->tx_pos = 0; + } + to_send = nvec->tx_size; + writel(to_send, nvec->base + I2C_SL_RCVD); + gpio_set_value(nvec_data.gpio, 1); + nvec->state = NVST_WRITE; + } else { + nvec->state = NVST_READ; + nvec->rx_buf[nvec->rx_pos] = (char)received; + ++nvec->rx_pos; + } + break; + + case NVST_READ: + if (nvec->rx_pos >= 34) { + error("NVEC io: read buffer is full\n"); + break; + } + nvec->rx_buf[nvec->rx_pos++] = (char)received; + if (status & END_TRANS) { + nvec_process_msg(nvec); + nvec->rx_pos = 0; + return nvec_io_read_ok; + } + break; + + case NVST_WRITE_SIZE: + to_send = nvec->tx_size; + writel(to_send, nvec->base + I2C_SL_RCVD); + nvec->state = NVST_WRITE; + break; + + case NVST_WRITE: + if (nvec->tx_pos >= nvec->tx_size) { + if (status & END_TRANS) + return nvec_io_write_ok; + + error("NVEC io: no data to write\n"); + return nvec_io_error; + } + to_send = nvec->tx_buf[nvec->tx_pos++]; + writel(to_send, nvec->base + I2C_SL_RCVD); + if (status & END_TRANS) { + nvec->tx_pos = 0; + nvec->tx_buf = 0; + return nvec_io_write_ok; + } + + break; + + default: + error("NVEC io: unknown state\n"); + break; + } + if (status & END_TRANS) + return nvec_io_retry; + } +} + + +/** + * Send request and read response. If write or read failed + * operation will be repeated NVEC_ATTEMPTS_MAX times. + * + * @param buf request data + * @param size request data size + * @return 0 if ok, -1 on error + */ +int nvec_do_request(char *buf, int size) +{ + int res = 0; + int i = 0; + + nvec_data.tx_buf = buf; + nvec_data.tx_size = size; + + while (i++ < NVEC_ATTEMPTS_MAX) { + nvec_data.tx_pos = 0; + + /* request */ + gpio_set_value(nvec_data.gpio, 0); + res = nvec_do_io(&nvec_data, NVEC_WAIT_FOR_EC); + if (res != nvec_io_write_ok) { + debug("warning: nvec failed to send request\n"); + continue; + } + + /* response */ + res = nvec_do_io(&nvec_data, NVEC_WAIT_FOR_EC); + if (res != nvec_io_read_ok) { + debug("warning: nvec failed to read response\n"); + continue; + } + + nvec_data.tx_buf = 0; + nvec_data.tx_size = 0; + nvec_data.tx_pos = 0; + + return 0; + } + + error("nvec failed to perform request\n"); + return -1; +} + + +/** + * Init i2c controller to operate in slave mode. + * + * @param nvec nvec state struct + */ +static void nvec_init_i2c_slave(struct nvec_t *nvec) +{ + unsigned long val; + + val = I2C_CNFG_NEW_MASTER_SFM | I2C_CNFG_PACKET_MODE_EN | + (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT); + writel(val, nvec->base + I2C_CNFG); + + /* i2c3 -> 67 */ + clock_start_periph_pll(67, CLOCK_ID_PERIPH, + nvec->i2c_clk * 8); + + reset_periph(67, 1); + + writel(I2C_SL_NEWSL, nvec->base + I2C_SL_CNFG); + writel(0x1E, nvec->base + I2C_SL_DELAY_COUNT); + + writel(nvec->i2c_addr>>1, nvec->base + I2C_SL_ADDR1); + writel(0, nvec->base + I2C_SL_ADDR2); + + funcmux_select(67, FUNCMUX_DEFAULT); +} + + +/** + * Decode the nvec information from the fdt. + * + * @param blob fdt blob + * @param config structure to store fdt config into + * @return 0 if ok, -ve on error + */ +static int nvec_decode_config(const void *blob, + struct fdt_nvec_config *config) +{ + int node; + + node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA20_NVEC); + if (node < 0) { + error("Cannot find NVEC node in fdt\n"); + return node; + } + + config->base_addr = fdtdec_get_addr(blob, node, "reg"); + if (config->base_addr == FDT_ADDR_T_NONE) { + error("No NVEC controller address\n"); + return -1; + } + + if (fdtdec_decode_gpio(blob, node, "request-gpios", + &config->request_gpio)) { + error("No NVEC request gpio\n"); + return -1; + } + + config->i2c_addr = fdtdec_get_int(blob, node, "slave-addr", -1); + config->i2c_clk = fdtdec_get_int(blob, node, "clock-frequency", -1); + + return 0; +} + + +int board_nvec_init(void) +{ + int res = 0; + + struct fdt_nvec_config cfg; + if (nvec_decode_config(gd->fdt_blob, &cfg)) { + debug("Can't parse NVEC node in device tree\n"); + return -1; + } + + nvec_data.rx_pos = 0; + nvec_data.tx_buf = 0; + nvec_data.tx_pos = 0; + nvec_data.tx_size = 0; + nvec_data.state = NVST_BEGIN; + + nvec_data.gpio = cfg.request_gpio.gpio; + nvec_data.i2c_addr = cfg.i2c_addr; + nvec_data.i2c_clk = cfg.i2c_clk; + nvec_data.base = (void __iomem *)cfg.base_addr; + + debug("NVEC initialization...\n"); + + res = gpio_request(nvec_data.gpio, NULL); + if (res != 0) + error("NVEC: err, gpio_request\n"); + res = gpio_direction_output(nvec_data.gpio, 1); + if (res != 0) + error("NVEC: err, gpio_direction\n"); + res = gpio_set_value(nvec_data.gpio, 1); + if (res != 0) + error("NVEC: err, gpio_set_value\n"); + udelay(100); + + nvec_init_i2c_slave(&nvec_data); + + nvec_enable_kbd_events(); + + return 1; +} + + +int nvec_read_events(void) +{ + int res; + int cnt = 0; + + while (++cnt <= 8) { + res = nvec_do_io(&nvec_data, NVEC_DONT_WAIT_FOR_EC); + switch (res) { + case nvec_io_not_ready: + return 0; + + case nvec_io_read_ok: + case nvec_io_retry: + break; + + case nvec_io_error: + case nvec_io_timeout: + debug("NVEC events: io failed %d\n", res); + return 0; + + case nvec_io_write_ok: + default: + debug("NVEC events: unexpected io result %d\n", res); + return 0; + } + } + + return 0; +} diff --git a/drivers/i2c/tegra_nvec_keyboard.c b/drivers/i2c/tegra_nvec_keyboard.c new file mode 100644 index 0000000..0837f08 --- /dev/null +++ b/drivers/i2c/tegra_nvec_keyboard.c @@ -0,0 +1,108 @@ +/* + * (C) Copyright 2013 + * Andrey Danin + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + + +circbuf_t key_buf = { 0, 0, NULL, NULL, NULL, NULL }; + +/* nvec commands */ +static char enable_kbd[] = { NVEC_KBD, ENABLE_KBD }; +static char reset_kbd[] = { NVEC_PS2, MOUSE_SEND_CMD, MOUSE_RESET, 3 }; +static char clear_leds[] = { NVEC_KBD, SET_LEDS, 0 }; + + +void nvec_push_key(unsigned short code, unsigned short state) +{ + int code_state; + + assert(key_buf.totalsize > 0); + + if (key_buf.size == key_buf.totalsize) + return; + + code_state = ((state << 16) | code); + buf_push(&key_buf, (const char *)&code_state, sizeof(code_state)); +} + + +int nvec_have_keys(void) +{ + return key_buf.size > 0; +} + + +int nvec_pop_key(void) +{ + int code_state; + int len = buf_pop(&key_buf, (char *)&code_state, sizeof(code_state)); + + if (len < sizeof(code_state)) + return -1; + + return code_state; +} + + +void nvec_process_keyboard_msg(const unsigned char *msg) +{ + int code, state; + int event_type; + int _size; + + event_type = nvec_msg_event_type(msg); + if (event_type != NVEC_KEYBOARD) + return; + + _size = (msg[0] & (3 << 5)) >> 5; + + if (_size == NVEC_VAR_SIZE) + return; + + if (_size == NVEC_3BYTES) + msg++; + + code = msg[1] & 0x7f; + state = msg[1] & 0x80; + + nvec_push_key(code_tabs[_size][code], state); +} + + +void nvec_enable_kbd_events(void) +{ + buf_init(&key_buf, NVEC_KEYS_QUEUE_SIZE * sizeof(int)); + + if (nvec_do_request(reset_kbd, 4)) + error("NVEC: failed to reset keyboard\n"); + if (nvec_do_request(clear_leds, 3)) + error("NVEC: failed to clear leds\n"); + if (nvec_do_request(enable_kbd, 2)) + error("NVEC: failed to enable keyboard\n"); + + debug("NVEC: keyboard initialization finished\n"); +} diff --git a/drivers/input/Makefile b/drivers/input/Makefile index a8e9be2..d1b1044 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_I8042_KBD) += i8042.o obj-$(CONFIG_TEGRA_KEYBOARD) += tegra-kbc.o +obj-$(CONFIG_TEGRA_NVEC_KEYBOARD) += tegra-nvec-kbc.o obj-$(CONFIG_CROS_EC_KEYB) += cros_ec_keyb.o ifdef CONFIG_PS2KBD obj-y += keyboard.o pc_keyb.o diff --git a/drivers/input/tegra-nvec-kbc.c b/drivers/input/tegra-nvec-kbc.c new file mode 100644 index 0000000..2799492 --- /dev/null +++ b/drivers/input/tegra-nvec-kbc.c @@ -0,0 +1,131 @@ +/* + * (C) Copyright 2011,2013 + * Andrey Danin + * NVIDIA Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include + +enum { + KBC_MAX_KPENT = 8, +}; + +/* keyboard config/state */ +static struct keyb { + struct input_config input; /* The input layer */ +} config; + + +/** + * Check the tegra nvec keyboard, and send any keys that are pressed. + * + * This is called by input_tstc() and input_getc() when they need more + * characters + * + * @param input Input configuration + * @return 1, to indicate that we have something to look at + */ +int tegra_nvec_kbc_check(struct input_config *input) +{ + int res = 0; + int fifo[KBC_MAX_KPENT]; + int cnt = 0; + + if (!nvec_have_keys()) + nvec_read_events(); + + while (nvec_have_keys() && cnt < KBC_MAX_KPENT) { + res = 1; + fifo[cnt++] = nvec_pop_key(); + if (cnt == KBC_MAX_KPENT) { + input_send_keycodes(input, fifo, cnt); + cnt = 0; + } + } + + if (cnt > 0) + input_send_keycodes(input, fifo, cnt); + + return res; +} + +/** + * Test if keys are available to be read + * + * @return 0 if no keys available, 1 if keys are available + */ +static int kbd_tstc(void) +{ + /* Just get input to do this for us */ + return input_tstc(&config.input); +} + +/** + * Read a key + * + * TODO: U-Boot wants 0 for no key, but Ctrl-@ is a valid key... + * + * @return ASCII key code, or 0 if no key, or -1 if error + */ +static int kbd_getc(void) +{ + /* Just get input to do this for us */ + return input_getc(&config.input); +} + + +int drv_keyboard_init(void) +{ + struct stdio_dev dev; + char *stdinname = getenv("stdin"); + int error; + + if (input_init(&config.input, 0)) { + printf("nvec kbc: cannot set up input\n"); + return -1; + } + config.input.read_keys = tegra_nvec_kbc_check; + + memset(&dev, '\0', sizeof(dev)); + strcpy(dev.name, "tegra-nvec-kbc"); + dev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM; + dev.getc = kbd_getc; + dev.tstc = kbd_tstc; + + /* Register the device. init_tegra_keyboard() will be called soon */ + error = input_stdio_register(&dev); + if (error) { + printf("nvec kbc: failed to register stdio device, %d\n", + error); + return error; + } +#ifdef CONFIG_CONSOLE_MUX + error = iomux_doenv(stdin, stdinname); + if (error) { + printf("nvec kbc: iomux_doenv failed, %d\n", error); + return error; + } +#endif + return 0; +} diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c index b52e9ed..0793f73 100644 --- a/drivers/video/cfb_console.c +++ b/drivers/video/cfb_console.c @@ -90,6 +90,7 @@ #include #include #include +#include /* * Console device defines with SMI graphic @@ -371,10 +372,7 @@ static u32 eorx, fgx, bgx; /* color pats */ static int cfb_do_flush_cache; #ifdef CONFIG_CFB_CONSOLE_ANSI -static char ansi_buf[10]; -static int ansi_buf_size; -static int ansi_colors_need_revert; -static int ansi_cursor_hidden; +struct ansi_console_t ansi_console; #endif static const int video_font_draw_table8[] = { @@ -866,7 +864,7 @@ static void console_swap_colors(void) static inline int console_cursor_is_visible(void) { - return !ansi_cursor_hidden; + return !ansi_console.ansi_cursor_hidden; } #else static inline int console_cursor_is_visible(void) @@ -947,210 +945,7 @@ static void parse_putc(const char c) void video_putc(const char c) { #ifdef CONFIG_CFB_CONSOLE_ANSI - int i; - - if (c == 27) { - for (i = 0; i < ansi_buf_size; ++i) - parse_putc(ansi_buf[i]); - ansi_buf[0] = 27; - ansi_buf_size = 1; - return; - } - - if (ansi_buf_size > 0) { - /* - * 0 - ESC - * 1 - [ - * 2 - num1 - * 3 - .. - * 4 - ; - * 5 - num2 - * 6 - .. - * - cchar - */ - int next = 0; - - int flush = 0; - int fail = 0; - - int num1 = 0; - int num2 = 0; - int cchar = 0; - - ansi_buf[ansi_buf_size++] = c; - - if (ansi_buf_size >= sizeof(ansi_buf)) - fail = 1; - - for (i = 0; i < ansi_buf_size; ++i) { - if (fail) - break; - - switch (next) { - case 0: - if (ansi_buf[i] == 27) - next = 1; - else - fail = 1; - break; - - case 1: - if (ansi_buf[i] == '[') - next = 2; - else - fail = 1; - break; - - case 2: - if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') { - num1 = ansi_buf[i]-'0'; - next = 3; - } else if (ansi_buf[i] != '?') { - --i; - num1 = 1; - next = 4; - } - break; - - case 3: - if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') { - num1 *= 10; - num1 += ansi_buf[i]-'0'; - } else { - --i; - next = 4; - } - break; - - case 4: - if (ansi_buf[i] != ';') { - --i; - next = 7; - } else - next = 5; - break; - - case 5: - if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') { - num2 = ansi_buf[i]-'0'; - next = 6; - } else - fail = 1; - break; - - case 6: - if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') { - num2 *= 10; - num2 += ansi_buf[i]-'0'; - } else { - --i; - next = 7; - } - break; - - case 7: - if ((ansi_buf[i] >= 'A' && ansi_buf[i] <= 'H') - || ansi_buf[i] == 'J' - || ansi_buf[i] == 'K' - || ansi_buf[i] == 'h' - || ansi_buf[i] == 'l' - || ansi_buf[i] == 'm') { - cchar = ansi_buf[i]; - flush = 1; - } else - fail = 1; - break; - } - } - - if (fail) { - for (i = 0; i < ansi_buf_size; ++i) - parse_putc(ansi_buf[i]); - ansi_buf_size = 0; - return; - } - - if (flush) { - if (!ansi_cursor_hidden) - CURSOR_OFF; - ansi_buf_size = 0; - switch (cchar) { - case 'A': - /* move cursor num1 rows up */ - console_cursor_up(num1); - break; - case 'B': - /* move cursor num1 rows down */ - console_cursor_down(num1); - break; - case 'C': - /* move cursor num1 columns forward */ - console_cursor_right(num1); - break; - case 'D': - /* move cursor num1 columns back */ - console_cursor_left(num1); - break; - case 'E': - /* move cursor num1 rows up at begin of row */ - console_previousline(num1); - break; - case 'F': - /* move cursor num1 rows down at begin of row */ - console_newline(num1); - break; - case 'G': - /* move cursor to column num1 */ - console_cursor_set_position(-1, num1-1); - break; - case 'H': - /* move cursor to row num1, column num2 */ - console_cursor_set_position(num1-1, num2-1); - break; - case 'J': - /* clear console and move cursor to 0, 0 */ - console_clear(); - console_cursor_set_position(0, 0); - break; - case 'K': - /* clear line */ - if (num1 == 0) - console_clear_line(console_row, - console_col, - CONSOLE_COLS-1); - else if (num1 == 1) - console_clear_line(console_row, - 0, console_col); - else - console_clear_line(console_row, - 0, CONSOLE_COLS-1); - break; - case 'h': - ansi_cursor_hidden = 0; - break; - case 'l': - ansi_cursor_hidden = 1; - break; - case 'm': - if (num1 == 0) { /* reset swapped colors */ - if (ansi_colors_need_revert) { - console_swap_colors(); - ansi_colors_need_revert = 0; - } - } else if (num1 == 7) { /* once swap colors */ - if (!ansi_colors_need_revert) { - console_swap_colors(); - ansi_colors_need_revert = 1; - } - } - break; - } - if (!ansi_cursor_hidden) - CURSOR_SET; - } - } else { - parse_putc(c); - } + ansi_putc(&ansi_console, c); #else parse_putc(c); #endif @@ -2233,6 +2028,32 @@ static int video_init(void) if (cfb_do_flush_cache) flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE); + memset(&ansi_console, 0, sizeof(ansi_console)); + ansi_console.putc = parse_putc; + +#if defined(CONFIG_CONSOLE_CURSOR) || defined(CONFIG_VIDEO_SW_CURSOR) + ansi_console.cursor_set = video_set_cursor; + ansi_console.cursor_enable = console_cursor; + /* TODO Add on/off */ +#endif + ansi_console.cursor_up = console_cursor_up; + ansi_console.cursor_up = console_cursor_up; + ansi_console.cursor_down = console_cursor_down; + ansi_console.cursor_left = console_cursor_left; + ansi_console.cursor_right = console_cursor_right; + ansi_console.previous_line = console_previousline; + ansi_console.new_line = console_newline; + + ansi_console.set_position = console_cursor_set_position; + + ansi_console.clear_line = console_clear_line; + + ansi_console.clear = console_clear; + ansi_console.swap_colors = console_swap_colors; + + ansi_console.console_col = &console_col; + ansi_console.console_row = &console_row; + return 0; } diff --git a/include/ansi_console.h b/include/ansi_console.h new file mode 100644 index 0000000..1f70747 --- /dev/null +++ b/include/ansi_console.h @@ -0,0 +1,42 @@ +/* + * (C) Copyright 2012 + * Pali Rohár + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * ANSI terminal + */ + +#include + +struct ansi_console_t { + void (*putc)(const char c); + + void (*cursor_set)(void); + void (*cursor_enable)(int enable); + void (*cursor_up)(int n); + void (*cursor_down)(int n); + void (*cursor_left)(int n); + void (*cursor_right)(int n); + void (*previous_line)(int n); + void (*new_line)(int n); + + void (*set_position)(int x, int y); + + void (*clear_line)(int n, int start, int end); + + void (*clear)(void); + void (*swap_colors)(void); + + int* console_col; + int* console_row; + + char ansi_buf[10]; + int ansi_buf_size; + int ansi_colors_need_revert; + int ansi_cursor_hidden; +}; + +void ansi_putc(struct ansi_console_t* console, const char c); diff --git a/include/configs/paz00.h b/include/configs/paz00.h index dd0abf8..429f9bf 100644 --- a/include/configs/paz00.h +++ b/include/configs/paz00.h @@ -72,6 +72,21 @@ #define CONFIG_SYS_WHITE_ON_BLACK #define CONFIG_CONSOLE_SCROLL_LINES 10 +/* Keyboard support */ +#define CONFIG_KEYBOARD +#define CONFIG_TEGRA_NVEC_KEYBOARD +/* NVEC support */ +#define CONFIG_TEGRA_I2C +#define CONFIG_SYS_I2C_INIT_BOARD +#define CONFIG_TEGRA_NVEC + +#define CONFIG_ANSI_CONSOLE +#define CONFIG_CMD_BOOTMENU +#define CONFIG_MENU +#define CONFIG_AUTOBOOT_KEYED + #include "tegra-common-post.h" +#define CONFIG_INITRD_TAG 1 + #endif /* __CONFIG_H */ diff --git a/include/configs/tegra-common-post.h b/include/configs/tegra-common-post.h index 1c770c9..2d0b07a 100644 --- a/include/configs/tegra-common-post.h +++ b/include/configs/tegra-common-post.h @@ -142,6 +142,8 @@ #ifdef CONFIG_TEGRA_KEYBOARD #define STDIN_KBD_KBC ",tegra-kbc" +#elif defined(CONFIG_TEGRA_NVEC_KEYBOARD) +#define STDIN_KBD_KBC ",tegra-nvec-kbc" #else #define STDIN_KBD_KBC "" #endif diff --git a/include/fdtdec.h b/include/fdtdec.h index a7e6ee7..5be662a 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -64,6 +64,7 @@ enum fdt_compat_id { COMPAT_NVIDIA_TEGRA20_SDMMC, /* Tegra20 SDMMC controller */ COMPAT_NVIDIA_TEGRA20_SFLASH, /* Tegra 2 SPI flash controller */ COMPAT_NVIDIA_TEGRA20_SLINK, /* Tegra 2 SPI SLINK controller */ + COMPAT_NVIDIA_TEGRA20_NVEC, /* Tegra 2 EC controller */ COMPAT_NVIDIA_TEGRA114_SPI, /* Tegra 114 SPI controller */ COMPAT_SMSC_LAN9215, /* SMSC 10/100 Ethernet LAN9215 */ COMPAT_SAMSUNG_EXYNOS5_SROMC, /* Exynos5 SROMC */ diff --git a/lib/Makefile b/lib/Makefile index 68210a5..edb6d0f 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_BZIP2) += bzlib_decompress.o obj-$(CONFIG_BZIP2) += bzlib_randtable.o obj-$(CONFIG_BZIP2) += bzlib_huffman.o obj-$(CONFIG_USB_TTY) += circbuf.o +obj-$(CONFIG_TEGRA_NVEC) += circbuf.o obj-y += crc7.o obj-y += crc8.o obj-y += crc16.o diff --git a/lib/fdtdec.c b/lib/fdtdec.c index aaa6620..06bea03 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -38,6 +38,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(NVIDIA_TEGRA20_SDMMC, "nvidia,tegra20-sdhci"), COMPAT(NVIDIA_TEGRA20_SFLASH, "nvidia,tegra20-sflash"), COMPAT(NVIDIA_TEGRA20_SLINK, "nvidia,tegra20-slink"), + COMPAT(NVIDIA_TEGRA20_NVEC, "nvidia,tegra20-nvec"), COMPAT(NVIDIA_TEGRA114_SPI, "nvidia,tegra114-spi"), COMPAT(SMSC_LAN9215, "smsc,lan9215"), COMPAT(SAMSUNG_EXYNOS5_SROMC, "samsung,exynos-sromc"),