blob: f99cfe7f4f0db6cf560dd0766cba3ab5224322da [file] [log] [blame]
wdenk91d32562002-09-18 21:21:13 +00001/*
Heiko Schocher3f4978c2012-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 Denk1a459662013-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 Glassb206cd72015-10-18 21:17:15 -060014#include <dm.h>
Simon Glassd97143a2014-07-23 06:55:05 -060015#include <errno.h>
wdenk91d32562002-09-18 21:21:13 +000016#include <stdarg.h>
17#include <malloc.h>
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +020018#include <stdio_dev.h>
wdenk281e00a2004-08-01 22:48:16 +000019#include <serial.h>
wdenk7f6c2cb2002-11-10 22:06:23 +000020#ifdef CONFIG_LOGBUFFER
21#include <logbuff.h>
22#endif
Heiko Schocherea818db2013-01-29 08:53:15 +010023
24#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)
wdenk91d32562002-09-18 21:21:13 +000025#include <i2c.h>
wdenk7f6c2cb2002-11-10 22:06:23 +000026#endif
wdenk91d32562002-09-18 21:21:13 +000027
Simon Glassb206cd72015-10-18 21:17:15 -060028#include <dm/device-internal.h>
29
Wolfgang Denkd87080b2006-03-31 18:32:53 +020030DECLARE_GLOBAL_DATA_PTR;
31
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +020032static struct stdio_dev devs;
33struct stdio_dev *stdio_devices[] = { NULL, NULL, NULL };
wdenk91d32562002-09-18 21:21:13 +000034char *stdio_names[MAX_FILES] = { "stdin", "stdout", "stderr" };
35
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020036#if defined(CONFIG_SPLASH_SCREEN) && !defined(CONFIG_SYS_DEVICE_NULLDEV)
37#define CONFIG_SYS_DEVICE_NULLDEV 1
wdenkd791b1d2003-04-20 14:04:18 +000038#endif
39
Hans de Goede32d01922014-09-20 16:54:37 +020040#ifdef CONFIG_SYS_STDIO_DEREGISTER
41#define CONFIG_SYS_DEVICE_NULLDEV 1
42#endif
wdenkd791b1d2003-04-20 14:04:18 +000043
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020044#ifdef CONFIG_SYS_DEVICE_NULLDEV
Jeroen Hofstee654f8d02014-10-08 22:57:44 +020045static void nulldev_putc(struct stdio_dev *dev, const char c)
wdenk91d32562002-09-18 21:21:13 +000046{
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +020047 /* nulldev is empty! */
wdenk91d32562002-09-18 21:21:13 +000048}
49
Jeroen Hofstee654f8d02014-10-08 22:57:44 +020050static void nulldev_puts(struct stdio_dev *dev, const char *s)
wdenk91d32562002-09-18 21:21:13 +000051{
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +020052 /* nulldev is empty! */
wdenk91d32562002-09-18 21:21:13 +000053}
54
Jeroen Hofstee654f8d02014-10-08 22:57:44 +020055static int nulldev_input(struct stdio_dev *dev)
wdenk91d32562002-09-18 21:21:13 +000056{
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +020057 /* nulldev is empty! */
58 return 0;
wdenk91d32562002-09-18 21:21:13 +000059}
60#endif
61
Jeroen Hofstee654f8d02014-10-08 22:57:44 +020062static void stdio_serial_putc(struct stdio_dev *dev, const char c)
Simon Glass709ea542014-07-23 06:54:59 -060063{
64 serial_putc(c);
65}
66
Jeroen Hofstee654f8d02014-10-08 22:57:44 +020067static void stdio_serial_puts(struct stdio_dev *dev, const char *s)
Simon Glass709ea542014-07-23 06:54:59 -060068{
69 serial_puts(s);
70}
71
Jeroen Hofstee654f8d02014-10-08 22:57:44 +020072static int stdio_serial_getc(struct stdio_dev *dev)
Simon Glass709ea542014-07-23 06:54:59 -060073{
74 return serial_getc();
75}
76
Jeroen Hofstee654f8d02014-10-08 22:57:44 +020077static int stdio_serial_tstc(struct stdio_dev *dev)
Simon Glass709ea542014-07-23 06:54:59 -060078{
79 return serial_tstc();
80}
81
wdenk91d32562002-09-18 21:21:13 +000082/**************************************************************************
83 * SYSTEM DRIVERS
84 **************************************************************************
85 */
86
87static void drv_system_init (void)
88{
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +020089 struct stdio_dev dev;
wdenk91d32562002-09-18 21:21:13 +000090
91 memset (&dev, 0, sizeof (dev));
92
93 strcpy (dev.name, "serial");
Bin Meng1caf9342015-11-03 23:23:37 -080094 dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;
Simon Glass709ea542014-07-23 06:54:59 -060095 dev.putc = stdio_serial_putc;
96 dev.puts = stdio_serial_puts;
97 dev.getc = stdio_serial_getc;
98 dev.tstc = stdio_serial_tstc;
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +020099 stdio_register (&dev);
wdenk91d32562002-09-18 21:21:13 +0000100
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200101#ifdef CONFIG_SYS_DEVICE_NULLDEV
wdenk91d32562002-09-18 21:21:13 +0000102 memset (&dev, 0, sizeof (dev));
103
104 strcpy (dev.name, "nulldev");
Bin Meng1caf9342015-11-03 23:23:37 -0800105 dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;
wdenk91d32562002-09-18 21:21:13 +0000106 dev.putc = nulldev_putc;
107 dev.puts = nulldev_puts;
108 dev.getc = nulldev_input;
109 dev.tstc = nulldev_input;
110
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200111 stdio_register (&dev);
wdenk91d32562002-09-18 21:21:13 +0000112#endif
113}
114
115/**************************************************************************
116 * DEVICES
117 **************************************************************************
118 */
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200119struct list_head* stdio_get_list(void)
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +0200120{
121 return &(devs.list);
122}
123
Mike Frysingerd7be3052010-10-20 07:18:03 -0400124struct stdio_dev* stdio_get_by_name(const char *name)
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +0200125{
126 struct list_head *pos;
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200127 struct stdio_dev *dev;
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +0200128
129 if(!name)
130 return NULL;
131
132 list_for_each(pos, &(devs.list)) {
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200133 dev = list_entry(pos, struct stdio_dev, list);
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +0200134 if(strcmp(dev->name, name) == 0)
135 return dev;
136 }
137
138 return NULL;
139}
140
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200141struct stdio_dev* stdio_clone(struct stdio_dev *dev)
Jean-Christophe PLAGNIOL-VILLARD628ffd72008-09-01 17:11:26 +0200142{
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200143 struct stdio_dev *_dev;
Jean-Christophe PLAGNIOL-VILLARD628ffd72008-09-01 17:11:26 +0200144
145 if(!dev)
146 return NULL;
147
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200148 _dev = calloc(1, sizeof(struct stdio_dev));
Jean-Christophe PLAGNIOL-VILLARD628ffd72008-09-01 17:11:26 +0200149
150 if(!_dev)
151 return NULL;
152
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200153 memcpy(_dev, dev, sizeof(struct stdio_dev));
Jean-Christophe PLAGNIOL-VILLARD628ffd72008-09-01 17:11:26 +0200154
155 return _dev;
156}
wdenk91d32562002-09-18 21:21:13 +0000157
Simon Glassd97143a2014-07-23 06:55:05 -0600158int stdio_register_dev(struct stdio_dev *dev, struct stdio_dev **devp)
wdenk91d32562002-09-18 21:21:13 +0000159{
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200160 struct stdio_dev *_dev;
Jean-Christophe PLAGNIOL-VILLARD628ffd72008-09-01 17:11:26 +0200161
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200162 _dev = stdio_clone(dev);
Jean-Christophe PLAGNIOL-VILLARD628ffd72008-09-01 17:11:26 +0200163 if(!_dev)
Simon Glassd97143a2014-07-23 06:55:05 -0600164 return -ENODEV;
Stefan Roese3e3c0262008-09-05 10:47:46 +0200165 list_add_tail(&(_dev->list), &(devs.list));
Simon Glassd97143a2014-07-23 06:55:05 -0600166 if (devp)
167 *devp = _dev;
168
wdenk91d32562002-09-18 21:21:13 +0000169 return 0;
170}
171
Simon Glassd97143a2014-07-23 06:55:05 -0600172int stdio_register(struct stdio_dev *dev)
173{
174 return stdio_register_dev(dev, NULL);
175}
176
wdenk91d32562002-09-18 21:21:13 +0000177/* deregister the device "devname".
178 * returns 0 if success, -1 if device is assigned and 1 if devname not found
179 */
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200180#ifdef CONFIG_SYS_STDIO_DEREGISTER
Hans de Goede32d01922014-09-20 16:54:37 +0200181int stdio_deregister_dev(struct stdio_dev *dev, int force)
wdenk91d32562002-09-18 21:21:13 +0000182{
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +0200183 int l;
184 struct list_head *pos;
Bradley Bolen03bf22f2011-08-22 11:48:05 +0000185 char temp_names[3][16];
wdenk91d32562002-09-18 21:21:13 +0000186
wdenk91d32562002-09-18 21:21:13 +0000187 /* get stdio devices (ListRemoveItem changes the dev list) */
188 for (l=0 ; l< MAX_FILES; l++) {
189 if (stdio_devices[l] == dev) {
Hans de Goede32d01922014-09-20 16:54:37 +0200190 if (force) {
191 strcpy(temp_names[l], "nulldev");
192 continue;
193 }
wdenk91d32562002-09-18 21:21:13 +0000194 /* Device is assigned -> report error */
195 return -1;
196 }
197 memcpy (&temp_names[l][0],
198 stdio_devices[l]->name,
Bradley Bolen03bf22f2011-08-22 11:48:05 +0000199 sizeof(temp_names[l]));
wdenk91d32562002-09-18 21:21:13 +0000200 }
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +0200201
202 list_del(&(dev->list));
Hans de Goede88274b62014-09-24 14:06:09 +0200203 free(dev);
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +0200204
wdenk91d32562002-09-18 21:21:13 +0000205 /* reassign Device list */
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +0200206 list_for_each(pos, &(devs.list)) {
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200207 dev = list_entry(pos, struct stdio_dev, list);
wdenk91d32562002-09-18 21:21:13 +0000208 for (l=0 ; l< MAX_FILES; l++) {
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +0200209 if(strcmp(dev->name, temp_names[l]) == 0)
wdenk91d32562002-09-18 21:21:13 +0000210 stdio_devices[l] = dev;
wdenk91d32562002-09-18 21:21:13 +0000211 }
212 }
213 return 0;
214}
Simon Glassd97143a2014-07-23 06:55:05 -0600215
Hans de Goede32d01922014-09-20 16:54:37 +0200216int stdio_deregister(const char *devname, int force)
Simon Glassd97143a2014-07-23 06:55:05 -0600217{
218 struct stdio_dev *dev;
219
220 dev = stdio_get_by_name(devname);
221
222 if (!dev) /* device not found */
223 return -ENODEV;
224
Hans de Goede32d01922014-09-20 16:54:37 +0200225 return stdio_deregister_dev(dev, force);
Simon Glassd97143a2014-07-23 06:55:05 -0600226}
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200227#endif /* CONFIG_SYS_STDIO_DEREGISTER */
wdenk91d32562002-09-18 21:21:13 +0000228
Simon Glass9fb02492014-09-03 17:37:01 -0600229int stdio_init_tables(void)
wdenk91d32562002-09-18 21:21:13 +0000230{
Wolfgang Denk2e5167c2010-10-28 20:00:11 +0200231#if defined(CONFIG_NEEDS_MANUAL_RELOC)
Peter Tyser521af042009-09-21 11:20:36 -0500232 /* already relocated for current ARM implementation */
wdenk91d32562002-09-18 21:21:13 +0000233 ulong relocation_offset = gd->reloc_off;
wdenk3595ac42003-06-22 17:18:28 +0000234 int i;
wdenk91d32562002-09-18 21:21:13 +0000235
236 /* relocate device name pointers */
237 for (i = 0; i < (sizeof (stdio_names) / sizeof (char *)); ++i) {
238 stdio_names[i] = (char *) (((ulong) stdio_names[i]) +
239 relocation_offset);
240 }
Wolfgang Denk2e5167c2010-10-28 20:00:11 +0200241#endif /* CONFIG_NEEDS_MANUAL_RELOC */
wdenk91d32562002-09-18 21:21:13 +0000242
243 /* Initialize the list */
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +0200244 INIT_LIST_HEAD(&(devs.list));
wdenk91d32562002-09-18 21:21:13 +0000245
Simon Glass9fb02492014-09-03 17:37:01 -0600246 return 0;
247}
248
249int stdio_add_devices(void)
250{
Simon Glassb206cd72015-10-18 21:17:15 -0600251#ifdef CONFIG_DM_KEYBOARD
252 struct udevice *dev;
253 struct uclass *uc;
254 int ret;
255
256 /*
257 * For now we probe all the devices here. At some point this should be
258 * done only when the devices are required - e.g. we have a list of
259 * input devices to start up in the stdin environment variable. That
260 * work probably makes more sense when stdio itself is converted to
261 * driver model.
262 *
263 * TODO(sjg@chromium.org): Convert changing uclass_first_device() etc.
264 * to return the device even on error. Then we could use that here.
265 */
266 ret = uclass_get(UCLASS_KEYBOARD, &uc);
267 if (ret)
268 return ret;
269
270 /* Don't report errors to the caller - assume that they are non-fatal */
271 uclass_foreach_dev(dev, uc) {
272 ret = device_probe(dev);
273 if (ret)
274 printf("Failed to probe keyboard '%s'\n", dev->name);
275 }
276#endif
Heiko Schocher3f4978c2012-01-16 21:12:24 +0000277#ifdef CONFIG_SYS_I2C
Heiko Schocher3f4978c2012-01-16 21:12:24 +0000278 i2c_init_all();
Heiko Schocher3f4978c2012-01-16 21:12:24 +0000279#else
Heiko Schocherea818db2013-01-29 08:53:15 +0100280#if defined(CONFIG_HARD_I2C)
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200281 i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
wdenk91d32562002-09-18 21:21:13 +0000282#endif
Heiko Schocher3f4978c2012-01-16 21:12:24 +0000283#endif
Simon Glasse3b81c12016-01-18 19:52:23 -0700284#ifdef CONFIG_DM_VIDEO
285 struct udevice *vdev;
Simon Glass35a1f0d2016-01-21 19:44:49 -0700286# ifndef CONFIG_DM_KEYBOARD
287 int ret;
288# endif
Simon Glasse3b81c12016-01-18 19:52:23 -0700289
290 for (ret = uclass_first_device(UCLASS_VIDEO, &vdev);
291 vdev;
292 ret = uclass_next_device(&vdev))
293 ;
294 if (ret)
295 printf("%s: Video device failed (ret=%d)\n", __func__, ret);
296#else
297# if defined(CONFIG_LCD)
wdenk91d32562002-09-18 21:21:13 +0000298 drv_lcd_init ();
Simon Glasse3b81c12016-01-18 19:52:23 -0700299# endif
300# if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
wdenk91d32562002-09-18 21:21:13 +0000301 drv_video_init ();
Simon Glasse3b81c12016-01-18 19:52:23 -0700302# endif
303#endif /* CONFIG_DM_VIDEO */
Simon Glassb206cd72015-10-18 21:17:15 -0600304#if defined(CONFIG_KEYBOARD) && !defined(CONFIG_DM_KEYBOARD)
wdenk682011f2003-06-03 23:54:09 +0000305 drv_keyboard_init ();
wdenk91d32562002-09-18 21:21:13 +0000306#endif
wdenk56f94be2002-11-05 16:35:14 +0000307#ifdef CONFIG_LOGBUFFER
308 drv_logbuff_init ();
309#endif
wdenk91d32562002-09-18 21:21:13 +0000310 drv_system_init ();
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200311 serial_stdio_init ();
wdenk232c1502004-03-12 00:14:09 +0000312#ifdef CONFIG_USB_TTY
313 drv_usbtty_init ();
314#endif
wdenk68ceb292004-08-02 21:11:11 +0000315#ifdef CONFIG_NETCONSOLE
316 drv_nc_init ();
317#endif
Mike Frysinger36ea8e92008-10-11 21:51:20 -0400318#ifdef CONFIG_JTAG_CONSOLE
319 drv_jtag_console_init ();
320#endif
Vadim Bendebury98ab4352012-10-12 18:48:47 +0000321#ifdef CONFIG_CBMEM_CONSOLE
322 cbmemc_init();
323#endif
Simon Glass9fb02492014-09-03 17:37:01 -0600324
325 return 0;
326}
327
328int stdio_init(void)
329{
330 stdio_init_tables();
331 stdio_add_devices();
332
333 return 0;
wdenk91d32562002-09-18 21:21:13 +0000334}