119b8fa0bSMarek Vasut /* 219b8fa0bSMarek Vasut * (C) Copyright 2000 319b8fa0bSMarek Vasut * Rob Taylor, Flying Pig Systems. robt@flyingpig.com. 419b8fa0bSMarek Vasut * 519b8fa0bSMarek Vasut * See file CREDITS for list of people who contributed to this 619b8fa0bSMarek Vasut * project. 719b8fa0bSMarek Vasut * 819b8fa0bSMarek Vasut * This program is free software; you can redistribute it and/or 919b8fa0bSMarek Vasut * modify it under the terms of the GNU General Public License as 1019b8fa0bSMarek Vasut * published by the Free Software Foundation; either version 2 of 1119b8fa0bSMarek Vasut * the License, or (at your option) any later version. 1219b8fa0bSMarek Vasut * 1319b8fa0bSMarek Vasut * This program is distributed in the hope that it will be useful, 1419b8fa0bSMarek Vasut * but WITHOUT ANY WARRANTY; without even the implied warranty of 1519b8fa0bSMarek Vasut * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1619b8fa0bSMarek Vasut * GNU General Public License for more details. 1719b8fa0bSMarek Vasut * 1819b8fa0bSMarek Vasut * You should have received a copy of the GNU General Public License 1919b8fa0bSMarek Vasut * along with this program; if not, write to the Free Software 2019b8fa0bSMarek Vasut * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 2119b8fa0bSMarek Vasut * MA 02111-1307 USA 2219b8fa0bSMarek Vasut */ 2319b8fa0bSMarek Vasut 2419b8fa0bSMarek Vasut #include <common.h> 2519b8fa0bSMarek Vasut #include <linux/compiler.h> 2619b8fa0bSMarek Vasut 2719b8fa0bSMarek Vasut #include <ns16550.h> 2819b8fa0bSMarek Vasut #ifdef CONFIG_NS87308 2919b8fa0bSMarek Vasut #include <ns87308.h> 3019b8fa0bSMarek Vasut #endif 3119b8fa0bSMarek Vasut 3219b8fa0bSMarek Vasut #include <serial.h> 3319b8fa0bSMarek Vasut 3448cbc3a8SScott Wood #ifndef CONFIG_NS16550_MIN_FUNCTIONS 3548cbc3a8SScott Wood 3619b8fa0bSMarek Vasut DECLARE_GLOBAL_DATA_PTR; 3719b8fa0bSMarek Vasut 3819b8fa0bSMarek Vasut #if !defined(CONFIG_CONS_INDEX) 3996708a06SAndrew Bradford #elif (CONFIG_CONS_INDEX < 1) || (CONFIG_CONS_INDEX > 6) 4019b8fa0bSMarek Vasut #error "Invalid console index value." 4119b8fa0bSMarek Vasut #endif 4219b8fa0bSMarek Vasut 4319b8fa0bSMarek Vasut #if CONFIG_CONS_INDEX == 1 && !defined(CONFIG_SYS_NS16550_COM1) 4419b8fa0bSMarek Vasut #error "Console port 1 defined but not configured." 4519b8fa0bSMarek Vasut #elif CONFIG_CONS_INDEX == 2 && !defined(CONFIG_SYS_NS16550_COM2) 4619b8fa0bSMarek Vasut #error "Console port 2 defined but not configured." 4719b8fa0bSMarek Vasut #elif CONFIG_CONS_INDEX == 3 && !defined(CONFIG_SYS_NS16550_COM3) 4819b8fa0bSMarek Vasut #error "Console port 3 defined but not configured." 4919b8fa0bSMarek Vasut #elif CONFIG_CONS_INDEX == 4 && !defined(CONFIG_SYS_NS16550_COM4) 5019b8fa0bSMarek Vasut #error "Console port 4 defined but not configured." 5196708a06SAndrew Bradford #elif CONFIG_CONS_INDEX == 5 && !defined(CONFIG_SYS_NS16550_COM5) 5296708a06SAndrew Bradford #error "Console port 5 defined but not configured." 5396708a06SAndrew Bradford #elif CONFIG_CONS_INDEX == 6 && !defined(CONFIG_SYS_NS16550_COM6) 5496708a06SAndrew Bradford #error "Console port 6 defined but not configured." 5519b8fa0bSMarek Vasut #endif 5619b8fa0bSMarek Vasut 5719b8fa0bSMarek Vasut /* Note: The port number specified in the functions is 1 based. 5819b8fa0bSMarek Vasut * the array is 0 based. 5919b8fa0bSMarek Vasut */ 6096708a06SAndrew Bradford static NS16550_t serial_ports[6] = { 6119b8fa0bSMarek Vasut #ifdef CONFIG_SYS_NS16550_COM1 6219b8fa0bSMarek Vasut (NS16550_t)CONFIG_SYS_NS16550_COM1, 6319b8fa0bSMarek Vasut #else 6419b8fa0bSMarek Vasut NULL, 6519b8fa0bSMarek Vasut #endif 6619b8fa0bSMarek Vasut #ifdef CONFIG_SYS_NS16550_COM2 6719b8fa0bSMarek Vasut (NS16550_t)CONFIG_SYS_NS16550_COM2, 6819b8fa0bSMarek Vasut #else 6919b8fa0bSMarek Vasut NULL, 7019b8fa0bSMarek Vasut #endif 7119b8fa0bSMarek Vasut #ifdef CONFIG_SYS_NS16550_COM3 7219b8fa0bSMarek Vasut (NS16550_t)CONFIG_SYS_NS16550_COM3, 7319b8fa0bSMarek Vasut #else 7419b8fa0bSMarek Vasut NULL, 7519b8fa0bSMarek Vasut #endif 7619b8fa0bSMarek Vasut #ifdef CONFIG_SYS_NS16550_COM4 7796708a06SAndrew Bradford (NS16550_t)CONFIG_SYS_NS16550_COM4, 7896708a06SAndrew Bradford #else 7996708a06SAndrew Bradford NULL, 8096708a06SAndrew Bradford #endif 8196708a06SAndrew Bradford #ifdef CONFIG_SYS_NS16550_COM5 8296708a06SAndrew Bradford (NS16550_t)CONFIG_SYS_NS16550_COM5, 8396708a06SAndrew Bradford #else 8496708a06SAndrew Bradford NULL, 8596708a06SAndrew Bradford #endif 8696708a06SAndrew Bradford #ifdef CONFIG_SYS_NS16550_COM6 8796708a06SAndrew Bradford (NS16550_t)CONFIG_SYS_NS16550_COM6 8819b8fa0bSMarek Vasut #else 8919b8fa0bSMarek Vasut NULL 9019b8fa0bSMarek Vasut #endif 9119b8fa0bSMarek Vasut }; 9219b8fa0bSMarek Vasut 9319b8fa0bSMarek Vasut #define PORT serial_ports[port-1] 9419b8fa0bSMarek Vasut 9519b8fa0bSMarek Vasut /* Multi serial device functions */ 9619b8fa0bSMarek Vasut #define DECLARE_ESERIAL_FUNCTIONS(port) \ 97ac63f2a2SKim Phillips static int eserial##port##_init(void) \ 98ac63f2a2SKim Phillips { \ 9919b8fa0bSMarek Vasut int clock_divisor; \ 10019b8fa0bSMarek Vasut clock_divisor = calc_divisor(serial_ports[port-1]); \ 10119b8fa0bSMarek Vasut NS16550_init(serial_ports[port-1], clock_divisor); \ 102ac63f2a2SKim Phillips return 0 ; \ 103ac63f2a2SKim Phillips } \ 104ac63f2a2SKim Phillips static void eserial##port##_setbrg(void) \ 105ac63f2a2SKim Phillips { \ 106ac63f2a2SKim Phillips serial_setbrg_dev(port); \ 107ac63f2a2SKim Phillips } \ 108ac63f2a2SKim Phillips static int eserial##port##_getc(void) \ 109ac63f2a2SKim Phillips { \ 110ac63f2a2SKim Phillips return serial_getc_dev(port); \ 111ac63f2a2SKim Phillips } \ 112ac63f2a2SKim Phillips static int eserial##port##_tstc(void) \ 113ac63f2a2SKim Phillips { \ 114ac63f2a2SKim Phillips return serial_tstc_dev(port); \ 115ac63f2a2SKim Phillips } \ 116ac63f2a2SKim Phillips static void eserial##port##_putc(const char c) \ 117ac63f2a2SKim Phillips { \ 118ac63f2a2SKim Phillips serial_putc_dev(port, c); \ 119ac63f2a2SKim Phillips } \ 120ac63f2a2SKim Phillips static void eserial##port##_puts(const char *s) \ 121ac63f2a2SKim Phillips { \ 122ac63f2a2SKim Phillips serial_puts_dev(port, s); \ 123ac63f2a2SKim Phillips } 12419b8fa0bSMarek Vasut 12519b8fa0bSMarek Vasut /* Serial device descriptor */ 12619b8fa0bSMarek Vasut #define INIT_ESERIAL_STRUCTURE(port, __name) { \ 12719b8fa0bSMarek Vasut .name = __name, \ 12819b8fa0bSMarek Vasut .start = eserial##port##_init, \ 12919b8fa0bSMarek Vasut .stop = NULL, \ 13019b8fa0bSMarek Vasut .setbrg = eserial##port##_setbrg, \ 13119b8fa0bSMarek Vasut .getc = eserial##port##_getc, \ 13219b8fa0bSMarek Vasut .tstc = eserial##port##_tstc, \ 13319b8fa0bSMarek Vasut .putc = eserial##port##_putc, \ 13419b8fa0bSMarek Vasut .puts = eserial##port##_puts, \ 13519b8fa0bSMarek Vasut } 13619b8fa0bSMarek Vasut 13719b8fa0bSMarek Vasut static int calc_divisor (NS16550_t port) 13819b8fa0bSMarek Vasut { 13919b8fa0bSMarek Vasut #ifdef CONFIG_OMAP1510 14019b8fa0bSMarek Vasut /* If can't cleanly clock 115200 set div to 1 */ 14119b8fa0bSMarek Vasut if ((CONFIG_SYS_NS16550_CLK == 12000000) && (gd->baudrate == 115200)) { 14219b8fa0bSMarek Vasut port->osc_12m_sel = OSC_12M_SEL; /* enable 6.5 * divisor */ 14319b8fa0bSMarek Vasut return (1); /* return 1 for base divisor */ 14419b8fa0bSMarek Vasut } 14519b8fa0bSMarek Vasut port->osc_12m_sel = 0; /* clear if previsouly set */ 14619b8fa0bSMarek Vasut #endif 14719b8fa0bSMarek Vasut #ifdef CONFIG_OMAP1610 14819b8fa0bSMarek Vasut /* If can't cleanly clock 115200 set div to 1 */ 14919b8fa0bSMarek Vasut if ((CONFIG_SYS_NS16550_CLK == 48000000) && (gd->baudrate == 115200)) { 15019b8fa0bSMarek Vasut return (26); /* return 26 for base divisor */ 15119b8fa0bSMarek Vasut } 15219b8fa0bSMarek Vasut #endif 15319b8fa0bSMarek Vasut 15419b8fa0bSMarek Vasut #ifdef CONFIG_APTIX 15519b8fa0bSMarek Vasut #define MODE_X_DIV 13 15619b8fa0bSMarek Vasut #else 15719b8fa0bSMarek Vasut #define MODE_X_DIV 16 15819b8fa0bSMarek Vasut #endif 15919b8fa0bSMarek Vasut 16019b8fa0bSMarek Vasut /* Compute divisor value. Normally, we should simply return: 16119b8fa0bSMarek Vasut * CONFIG_SYS_NS16550_CLK) / MODE_X_DIV / gd->baudrate 16219b8fa0bSMarek Vasut * but we need to round that value by adding 0.5. 16319b8fa0bSMarek Vasut * Rounding is especially important at high baud rates. 16419b8fa0bSMarek Vasut */ 16519b8fa0bSMarek Vasut return (CONFIG_SYS_NS16550_CLK + (gd->baudrate * (MODE_X_DIV / 2))) / 16619b8fa0bSMarek Vasut (MODE_X_DIV * gd->baudrate); 16719b8fa0bSMarek Vasut } 16819b8fa0bSMarek Vasut 16919b8fa0bSMarek Vasut void 17019b8fa0bSMarek Vasut _serial_putc(const char c,const int port) 17119b8fa0bSMarek Vasut { 17219b8fa0bSMarek Vasut if (c == '\n') 17319b8fa0bSMarek Vasut NS16550_putc(PORT, '\r'); 17419b8fa0bSMarek Vasut 17519b8fa0bSMarek Vasut NS16550_putc(PORT, c); 17619b8fa0bSMarek Vasut } 17719b8fa0bSMarek Vasut 17819b8fa0bSMarek Vasut void 17919b8fa0bSMarek Vasut _serial_putc_raw(const char c,const int port) 18019b8fa0bSMarek Vasut { 18119b8fa0bSMarek Vasut NS16550_putc(PORT, c); 18219b8fa0bSMarek Vasut } 18319b8fa0bSMarek Vasut 18419b8fa0bSMarek Vasut void 18519b8fa0bSMarek Vasut _serial_puts (const char *s,const int port) 18619b8fa0bSMarek Vasut { 18719b8fa0bSMarek Vasut while (*s) { 18819b8fa0bSMarek Vasut _serial_putc (*s++,port); 18919b8fa0bSMarek Vasut } 19019b8fa0bSMarek Vasut } 19119b8fa0bSMarek Vasut 19219b8fa0bSMarek Vasut 19319b8fa0bSMarek Vasut int 19419b8fa0bSMarek Vasut _serial_getc(const int port) 19519b8fa0bSMarek Vasut { 19619b8fa0bSMarek Vasut return NS16550_getc(PORT); 19719b8fa0bSMarek Vasut } 19819b8fa0bSMarek Vasut 19919b8fa0bSMarek Vasut int 20019b8fa0bSMarek Vasut _serial_tstc(const int port) 20119b8fa0bSMarek Vasut { 20219b8fa0bSMarek Vasut return NS16550_tstc(PORT); 20319b8fa0bSMarek Vasut } 20419b8fa0bSMarek Vasut 20519b8fa0bSMarek Vasut void 20619b8fa0bSMarek Vasut _serial_setbrg (const int port) 20719b8fa0bSMarek Vasut { 20819b8fa0bSMarek Vasut int clock_divisor; 20919b8fa0bSMarek Vasut 21019b8fa0bSMarek Vasut clock_divisor = calc_divisor(PORT); 21119b8fa0bSMarek Vasut NS16550_reinit(PORT, clock_divisor); 21219b8fa0bSMarek Vasut } 21319b8fa0bSMarek Vasut 21419b8fa0bSMarek Vasut static inline void 21519b8fa0bSMarek Vasut serial_putc_dev(unsigned int dev_index,const char c) 21619b8fa0bSMarek Vasut { 21719b8fa0bSMarek Vasut _serial_putc(c,dev_index); 21819b8fa0bSMarek Vasut } 21919b8fa0bSMarek Vasut 22019b8fa0bSMarek Vasut static inline void 22119b8fa0bSMarek Vasut serial_putc_raw_dev(unsigned int dev_index,const char c) 22219b8fa0bSMarek Vasut { 22319b8fa0bSMarek Vasut _serial_putc_raw(c,dev_index); 22419b8fa0bSMarek Vasut } 22519b8fa0bSMarek Vasut 22619b8fa0bSMarek Vasut static inline void 22719b8fa0bSMarek Vasut serial_puts_dev(unsigned int dev_index,const char *s) 22819b8fa0bSMarek Vasut { 22919b8fa0bSMarek Vasut _serial_puts(s,dev_index); 23019b8fa0bSMarek Vasut } 23119b8fa0bSMarek Vasut 23219b8fa0bSMarek Vasut static inline int 23319b8fa0bSMarek Vasut serial_getc_dev(unsigned int dev_index) 23419b8fa0bSMarek Vasut { 23519b8fa0bSMarek Vasut return _serial_getc(dev_index); 23619b8fa0bSMarek Vasut } 23719b8fa0bSMarek Vasut 23819b8fa0bSMarek Vasut static inline int 23919b8fa0bSMarek Vasut serial_tstc_dev(unsigned int dev_index) 24019b8fa0bSMarek Vasut { 24119b8fa0bSMarek Vasut return _serial_tstc(dev_index); 24219b8fa0bSMarek Vasut } 24319b8fa0bSMarek Vasut 24419b8fa0bSMarek Vasut static inline void 24519b8fa0bSMarek Vasut serial_setbrg_dev(unsigned int dev_index) 24619b8fa0bSMarek Vasut { 24719b8fa0bSMarek Vasut _serial_setbrg(dev_index); 24819b8fa0bSMarek Vasut } 24919b8fa0bSMarek Vasut 250*55db9ccaSScott Wood #if defined(CONFIG_SYS_NS16550_COM1) 25119b8fa0bSMarek Vasut DECLARE_ESERIAL_FUNCTIONS(1); 25219b8fa0bSMarek Vasut struct serial_device eserial1_device = 25319b8fa0bSMarek Vasut INIT_ESERIAL_STRUCTURE(1, "eserial0"); 254*55db9ccaSScott Wood #endif 255*55db9ccaSScott Wood #if defined(CONFIG_SYS_NS16550_COM2) 25619b8fa0bSMarek Vasut DECLARE_ESERIAL_FUNCTIONS(2); 25719b8fa0bSMarek Vasut struct serial_device eserial2_device = 25819b8fa0bSMarek Vasut INIT_ESERIAL_STRUCTURE(2, "eserial1"); 259*55db9ccaSScott Wood #endif 260*55db9ccaSScott Wood #if defined(CONFIG_SYS_NS16550_COM3) 26119b8fa0bSMarek Vasut DECLARE_ESERIAL_FUNCTIONS(3); 26219b8fa0bSMarek Vasut struct serial_device eserial3_device = 26319b8fa0bSMarek Vasut INIT_ESERIAL_STRUCTURE(3, "eserial2"); 264*55db9ccaSScott Wood #endif 265*55db9ccaSScott Wood #if defined(CONFIG_SYS_NS16550_COM4) 26619b8fa0bSMarek Vasut DECLARE_ESERIAL_FUNCTIONS(4); 26719b8fa0bSMarek Vasut struct serial_device eserial4_device = 26819b8fa0bSMarek Vasut INIT_ESERIAL_STRUCTURE(4, "eserial3"); 269*55db9ccaSScott Wood #endif 270*55db9ccaSScott Wood #if defined(CONFIG_SYS_NS16550_COM5) 27196708a06SAndrew Bradford DECLARE_ESERIAL_FUNCTIONS(5); 27296708a06SAndrew Bradford struct serial_device eserial5_device = 27396708a06SAndrew Bradford INIT_ESERIAL_STRUCTURE(5, "eserial4"); 274*55db9ccaSScott Wood #endif 275*55db9ccaSScott Wood #if defined(CONFIG_SYS_NS16550_COM6) 27696708a06SAndrew Bradford DECLARE_ESERIAL_FUNCTIONS(6); 27796708a06SAndrew Bradford struct serial_device eserial6_device = 27896708a06SAndrew Bradford INIT_ESERIAL_STRUCTURE(6, "eserial5"); 279*55db9ccaSScott Wood #endif 28019b8fa0bSMarek Vasut 28119b8fa0bSMarek Vasut __weak struct serial_device *default_serial_console(void) 28219b8fa0bSMarek Vasut { 28319b8fa0bSMarek Vasut #if CONFIG_CONS_INDEX == 1 28419b8fa0bSMarek Vasut return &eserial1_device; 28519b8fa0bSMarek Vasut #elif CONFIG_CONS_INDEX == 2 28619b8fa0bSMarek Vasut return &eserial2_device; 28719b8fa0bSMarek Vasut #elif CONFIG_CONS_INDEX == 3 28819b8fa0bSMarek Vasut return &eserial3_device; 28919b8fa0bSMarek Vasut #elif CONFIG_CONS_INDEX == 4 29019b8fa0bSMarek Vasut return &eserial4_device; 29196708a06SAndrew Bradford #elif CONFIG_CONS_INDEX == 5 29296708a06SAndrew Bradford return &eserial5_device; 29396708a06SAndrew Bradford #elif CONFIG_CONS_INDEX == 6 29496708a06SAndrew Bradford return &eserial6_device; 29519b8fa0bSMarek Vasut #else 29619b8fa0bSMarek Vasut #error "Bad CONFIG_CONS_INDEX." 29719b8fa0bSMarek Vasut #endif 29819b8fa0bSMarek Vasut } 29919b8fa0bSMarek Vasut 30019b8fa0bSMarek Vasut void ns16550_serial_initialize(void) 30119b8fa0bSMarek Vasut { 30219b8fa0bSMarek Vasut #if defined(CONFIG_SYS_NS16550_COM1) 30319b8fa0bSMarek Vasut serial_register(&eserial1_device); 30419b8fa0bSMarek Vasut #endif 30519b8fa0bSMarek Vasut #if defined(CONFIG_SYS_NS16550_COM2) 30619b8fa0bSMarek Vasut serial_register(&eserial2_device); 30719b8fa0bSMarek Vasut #endif 30819b8fa0bSMarek Vasut #if defined(CONFIG_SYS_NS16550_COM3) 30919b8fa0bSMarek Vasut serial_register(&eserial3_device); 31019b8fa0bSMarek Vasut #endif 31119b8fa0bSMarek Vasut #if defined(CONFIG_SYS_NS16550_COM4) 31219b8fa0bSMarek Vasut serial_register(&eserial4_device); 31319b8fa0bSMarek Vasut #endif 31496708a06SAndrew Bradford #if defined(CONFIG_SYS_NS16550_COM5) 31596708a06SAndrew Bradford serial_register(&eserial5_device); 31696708a06SAndrew Bradford #endif 31796708a06SAndrew Bradford #if defined(CONFIG_SYS_NS16550_COM6) 31896708a06SAndrew Bradford serial_register(&eserial6_device); 31996708a06SAndrew Bradford #endif 32019b8fa0bSMarek Vasut } 32148cbc3a8SScott Wood 32248cbc3a8SScott Wood #endif /* !CONFIG_NS16550_MIN_FUNCTIONS */ 323