blob: 692ca7f1cdf595ddb548673b4131983e41e2a6b1 [file] [log] [blame]
wdenk91d32562002-09-18 21:21:13 +00001/*
Heiko Schochere0e55bc2012-01-16 21:12:24 +00002 * Copyright (C) 2009 Sergey Kubushyn <ksi@koi8.net>
3 *
4 * Changes for multibus/multiadapter I2C support.
5 *
wdenk91d32562002-09-18 21:21:13 +00006 * (C) Copyright 2000
7 * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
8 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02009 * SPDX-License-Identifier: GPL-2.0+
wdenk91d32562002-09-18 21:21:13 +000010 */
11
12#include <config.h>
13#include <common.h>
Simon Glass5d609ce2014-07-23 06:55:05 -060014#include <errno.h>
wdenk91d32562002-09-18 21:21:13 +000015#include <stdarg.h>
16#include <malloc.h>
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +020017#include <stdio_dev.h>
wdenk7ac16102004-08-01 22:48:16 +000018#include <serial.h>
wdenk1272e232002-11-10 22:06:23 +000019#ifdef CONFIG_LOGBUFFER
20#include <logbuff.h>
21#endif
Heiko Schocher479a4cf2013-01-29 08:53:15 +010022
23#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)
wdenk91d32562002-09-18 21:21:13 +000024#include <i2c.h>
wdenk1272e232002-11-10 22:06:23 +000025#endif
wdenk91d32562002-09-18 21:21:13 +000026
Wolfgang Denk6405a152006-03-31 18:32:53 +020027DECLARE_GLOBAL_DATA_PTR;
28
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +020029static struct stdio_dev devs;
30struct stdio_dev *stdio_devices[] = { NULL, NULL, NULL };
wdenk91d32562002-09-18 21:21:13 +000031char *stdio_names[MAX_FILES] = { "stdin", "stdout", "stderr" };
32
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020033#if defined(CONFIG_SPLASH_SCREEN) && !defined(CONFIG_SYS_DEVICE_NULLDEV)
34#define CONFIG_SYS_DEVICE_NULLDEV 1
wdenk92bbe3f2003-04-20 14:04:18 +000035#endif
36
37
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020038#ifdef CONFIG_SYS_DEVICE_NULLDEV
Simon Glass0d1e1f72014-07-23 06:54:59 -060039void nulldev_putc(struct stdio_dev *dev, const char c)
wdenk91d32562002-09-18 21:21:13 +000040{
Jean-Christophe PLAGNIOL-VILLARD8a4a7842008-08-31 04:24:55 +020041 /* nulldev is empty! */
wdenk91d32562002-09-18 21:21:13 +000042}
43
Simon Glass0d1e1f72014-07-23 06:54:59 -060044void nulldev_puts(struct stdio_dev *dev, const char *s)
wdenk91d32562002-09-18 21:21:13 +000045{
Jean-Christophe PLAGNIOL-VILLARD8a4a7842008-08-31 04:24:55 +020046 /* nulldev is empty! */
wdenk91d32562002-09-18 21:21:13 +000047}
48
Simon Glass0d1e1f72014-07-23 06:54:59 -060049int nulldev_input(struct stdio_dev *dev)
wdenk91d32562002-09-18 21:21:13 +000050{
Jean-Christophe PLAGNIOL-VILLARD8a4a7842008-08-31 04:24:55 +020051 /* nulldev is empty! */
52 return 0;
wdenk91d32562002-09-18 21:21:13 +000053}
54#endif
55
Simon Glass0d1e1f72014-07-23 06:54:59 -060056void stdio_serial_putc(struct stdio_dev *dev, const char c)
57{
58 serial_putc(c);
59}
60
61void stdio_serial_puts(struct stdio_dev *dev, const char *s)
62{
63 serial_puts(s);
64}
65
66int stdio_serial_getc(struct stdio_dev *dev)
67{
68 return serial_getc();
69}
70
71int stdio_serial_tstc(struct stdio_dev *dev)
72{
73 return serial_tstc();
74}
75
wdenk91d32562002-09-18 21:21:13 +000076/**************************************************************************
77 * SYSTEM DRIVERS
78 **************************************************************************
79 */
80
81static void drv_system_init (void)
82{
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +020083 struct stdio_dev dev;
wdenk91d32562002-09-18 21:21:13 +000084
85 memset (&dev, 0, sizeof (dev));
86
87 strcpy (dev.name, "serial");
88 dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
Simon Glass0d1e1f72014-07-23 06:54:59 -060089 dev.putc = stdio_serial_putc;
90 dev.puts = stdio_serial_puts;
91 dev.getc = stdio_serial_getc;
92 dev.tstc = stdio_serial_tstc;
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +020093 stdio_register (&dev);
wdenk91d32562002-09-18 21:21:13 +000094
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020095#ifdef CONFIG_SYS_DEVICE_NULLDEV
wdenk91d32562002-09-18 21:21:13 +000096 memset (&dev, 0, sizeof (dev));
97
98 strcpy (dev.name, "nulldev");
99 dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
100 dev.putc = nulldev_putc;
101 dev.puts = nulldev_puts;
102 dev.getc = nulldev_input;
103 dev.tstc = nulldev_input;
104
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200105 stdio_register (&dev);
wdenk91d32562002-09-18 21:21:13 +0000106#endif
107}
108
109/**************************************************************************
110 * DEVICES
111 **************************************************************************
112 */
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200113struct list_head* stdio_get_list(void)
Jean-Christophe PLAGNIOL-VILLARD8a4a7842008-08-31 04:24:55 +0200114{
115 return &(devs.list);
116}
117
Mike Frysingere3d55722010-10-20 07:18:03 -0400118struct stdio_dev* stdio_get_by_name(const char *name)
Jean-Christophe PLAGNIOL-VILLARD8a4a7842008-08-31 04:24:55 +0200119{
120 struct list_head *pos;
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200121 struct stdio_dev *dev;
Jean-Christophe PLAGNIOL-VILLARD8a4a7842008-08-31 04:24:55 +0200122
123 if(!name)
124 return NULL;
125
126 list_for_each(pos, &(devs.list)) {
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200127 dev = list_entry(pos, struct stdio_dev, list);
Jean-Christophe PLAGNIOL-VILLARD8a4a7842008-08-31 04:24:55 +0200128 if(strcmp(dev->name, name) == 0)
129 return dev;
130 }
131
132 return NULL;
133}
134
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200135struct stdio_dev* stdio_clone(struct stdio_dev *dev)
Jean-Christophe PLAGNIOL-VILLARD3d85c432008-09-01 17:11:26 +0200136{
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200137 struct stdio_dev *_dev;
Jean-Christophe PLAGNIOL-VILLARD3d85c432008-09-01 17:11:26 +0200138
139 if(!dev)
140 return NULL;
141
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200142 _dev = calloc(1, sizeof(struct stdio_dev));
Jean-Christophe PLAGNIOL-VILLARD3d85c432008-09-01 17:11:26 +0200143
144 if(!_dev)
145 return NULL;
146
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200147 memcpy(_dev, dev, sizeof(struct stdio_dev));
Jean-Christophe PLAGNIOL-VILLARD3d85c432008-09-01 17:11:26 +0200148
149 return _dev;
150}
wdenk91d32562002-09-18 21:21:13 +0000151
Simon Glass5d609ce2014-07-23 06:55:05 -0600152int stdio_register_dev(struct stdio_dev *dev, struct stdio_dev **devp)
wdenk91d32562002-09-18 21:21:13 +0000153{
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200154 struct stdio_dev *_dev;
Jean-Christophe PLAGNIOL-VILLARD3d85c432008-09-01 17:11:26 +0200155
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200156 _dev = stdio_clone(dev);
Jean-Christophe PLAGNIOL-VILLARD3d85c432008-09-01 17:11:26 +0200157 if(!_dev)
Simon Glass5d609ce2014-07-23 06:55:05 -0600158 return -ENODEV;
Stefan Roesec3be13b2008-09-05 10:47:46 +0200159 list_add_tail(&(_dev->list), &(devs.list));
Simon Glass5d609ce2014-07-23 06:55:05 -0600160 if (devp)
161 *devp = _dev;
162
wdenk91d32562002-09-18 21:21:13 +0000163 return 0;
164}
165
Simon Glass5d609ce2014-07-23 06:55:05 -0600166int stdio_register(struct stdio_dev *dev)
167{
168 return stdio_register_dev(dev, NULL);
169}
170
wdenk91d32562002-09-18 21:21:13 +0000171/* deregister the device "devname".
172 * returns 0 if success, -1 if device is assigned and 1 if devname not found
173 */
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200174#ifdef CONFIG_SYS_STDIO_DEREGISTER
Simon Glass5d609ce2014-07-23 06:55:05 -0600175int stdio_deregister_dev(struct stdio_dev *dev)
wdenk91d32562002-09-18 21:21:13 +0000176{
Jean-Christophe PLAGNIOL-VILLARD8a4a7842008-08-31 04:24:55 +0200177 int l;
178 struct list_head *pos;
Bradley Bolen466d7392011-08-22 11:48:05 +0000179 char temp_names[3][16];
wdenk91d32562002-09-18 21:21:13 +0000180
wdenk91d32562002-09-18 21:21:13 +0000181 /* get stdio devices (ListRemoveItem changes the dev list) */
182 for (l=0 ; l< MAX_FILES; l++) {
183 if (stdio_devices[l] == dev) {
184 /* Device is assigned -> report error */
185 return -1;
186 }
187 memcpy (&temp_names[l][0],
188 stdio_devices[l]->name,
Bradley Bolen466d7392011-08-22 11:48:05 +0000189 sizeof(temp_names[l]));
wdenk91d32562002-09-18 21:21:13 +0000190 }
Jean-Christophe PLAGNIOL-VILLARD8a4a7842008-08-31 04:24:55 +0200191
192 list_del(&(dev->list));
193
wdenk91d32562002-09-18 21:21:13 +0000194 /* reassign Device list */
Jean-Christophe PLAGNIOL-VILLARD8a4a7842008-08-31 04:24:55 +0200195 list_for_each(pos, &(devs.list)) {
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200196 dev = list_entry(pos, struct stdio_dev, list);
wdenk91d32562002-09-18 21:21:13 +0000197 for (l=0 ; l< MAX_FILES; l++) {
Jean-Christophe PLAGNIOL-VILLARD8a4a7842008-08-31 04:24:55 +0200198 if(strcmp(dev->name, temp_names[l]) == 0)
wdenk91d32562002-09-18 21:21:13 +0000199 stdio_devices[l] = dev;
wdenk91d32562002-09-18 21:21:13 +0000200 }
201 }
202 return 0;
203}
Simon Glass5d609ce2014-07-23 06:55:05 -0600204
205int stdio_deregister(const char *devname)
206{
207 struct stdio_dev *dev;
208
209 dev = stdio_get_by_name(devname);
210
211 if (!dev) /* device not found */
212 return -ENODEV;
213
214 return stdio_deregister_dev(dev);
215}
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200216#endif /* CONFIG_SYS_STDIO_DEREGISTER */
wdenk91d32562002-09-18 21:21:13 +0000217
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200218int stdio_init (void)
wdenk91d32562002-09-18 21:21:13 +0000219{
Wolfgang Denkd0813e52010-10-28 20:00:11 +0200220#if defined(CONFIG_NEEDS_MANUAL_RELOC)
Peter Tyser9057cbf2009-09-21 11:20:36 -0500221 /* already relocated for current ARM implementation */
wdenk91d32562002-09-18 21:21:13 +0000222 ulong relocation_offset = gd->reloc_off;
wdenk56958612003-06-22 17:18:28 +0000223 int i;
wdenk91d32562002-09-18 21:21:13 +0000224
225 /* relocate device name pointers */
226 for (i = 0; i < (sizeof (stdio_names) / sizeof (char *)); ++i) {
227 stdio_names[i] = (char *) (((ulong) stdio_names[i]) +
228 relocation_offset);
229 }
Wolfgang Denkd0813e52010-10-28 20:00:11 +0200230#endif /* CONFIG_NEEDS_MANUAL_RELOC */
wdenk91d32562002-09-18 21:21:13 +0000231
232 /* Initialize the list */
Jean-Christophe PLAGNIOL-VILLARD8a4a7842008-08-31 04:24:55 +0200233 INIT_LIST_HEAD(&(devs.list));
wdenk91d32562002-09-18 21:21:13 +0000234
Heiko Schochere0e55bc2012-01-16 21:12:24 +0000235#ifdef CONFIG_SYS_I2C
Heiko Schochere0e55bc2012-01-16 21:12:24 +0000236 i2c_init_all();
Heiko Schochere0e55bc2012-01-16 21:12:24 +0000237#else
Heiko Schocher479a4cf2013-01-29 08:53:15 +0100238#if defined(CONFIG_HARD_I2C)
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200239 i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
wdenk91d32562002-09-18 21:21:13 +0000240#endif
Heiko Schochere0e55bc2012-01-16 21:12:24 +0000241#endif
wdenk91d32562002-09-18 21:21:13 +0000242#ifdef CONFIG_LCD
243 drv_lcd_init ();
244#endif
wdenk9dd2b882002-12-03 21:28:10 +0000245#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
wdenk91d32562002-09-18 21:21:13 +0000246 drv_video_init ();
247#endif
wdenk4e112c12003-06-03 23:54:09 +0000248#ifdef CONFIG_KEYBOARD
249 drv_keyboard_init ();
wdenk91d32562002-09-18 21:21:13 +0000250#endif
wdenk56f94be2002-11-05 16:35:14 +0000251#ifdef CONFIG_LOGBUFFER
252 drv_logbuff_init ();
253#endif
wdenk91d32562002-09-18 21:21:13 +0000254 drv_system_init ();
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200255 serial_stdio_init ();
wdenk29e7f5a2004-03-12 00:14:09 +0000256#ifdef CONFIG_USB_TTY
257 drv_usbtty_init ();
258#endif
wdenkb8fb6192004-08-02 21:11:11 +0000259#ifdef CONFIG_NETCONSOLE
260 drv_nc_init ();
261#endif
Mike Frysinger7504e972008-10-11 21:51:20 -0400262#ifdef CONFIG_JTAG_CONSOLE
263 drv_jtag_console_init ();
264#endif
Vadim Bendebury263a8bd2012-10-12 18:48:47 +0000265#ifdef CONFIG_CBMEM_CONSOLE
266 cbmemc_init();
267#endif
wdenk91d32562002-09-18 21:21:13 +0000268 return (0);
269}