summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/boards/animeo_ip/init.c88
-rw-r--r--arch/arm/configs/animeo_ip_defconfig1
-rw-r--r--common/console_common.c13
-rw-r--r--common/startup.c4
-rw-r--r--drivers/serial/atmel.c27
-rw-r--r--include/common.h1
-rw-r--r--include/console.h8
7 files changed, 136 insertions, 6 deletions
diff --git a/arch/arm/boards/animeo_ip/init.c b/arch/arm/boards/animeo_ip/init.c
index 81a8cdf..2fee1ff 100644
--- a/arch/arm/boards/animeo_ip/init.c
+++ b/arch/arm/boards/animeo_ip/init.c
@@ -327,20 +327,37 @@ static int animeo_ip_devices_init(void)
device_initcall(animeo_ip_devices_init);
-static int animeo_ip_console_init(void)
+static struct device_d *usart0, *usart1;
+
+static void animeo_ip_shutdown_uart(void *base)
+{
+#define ATMEL_US_BRGR 0x0020
+ writel(0, base + ATMEL_US_BRGR);
+}
+
+static void animeo_ip_shutdown(void)
{
/*
- * disable the dbgu enable by the bootstrap
+ * disable the dbgu and others enable by the bootstrap
* so linux can detect that we only enable the uart2
* and use it for decompress
*/
-#define ATMEL_US_BRGR 0x0020
- at91_sys_write(AT91_DBGU + ATMEL_US_BRGR, 0);
+ animeo_ip_shutdown_uart(IOMEM(AT91_DBGU + AT91_BASE_SYS));
+ animeo_ip_shutdown_uart(IOMEM(AT91SAM9260_BASE_US0));
+ animeo_ip_shutdown_uart(IOMEM(AT91SAM9260_BASE_US1));
+}
+
+static int animeo_ip_console_init(void)
+{
+ at91_register_uart(3, 0);
+
+ usart0 = at91_register_uart(1, ATMEL_UART_RTS);
+ usart1 = at91_register_uart(2, ATMEL_UART_RTS);
+ board_shutdown = animeo_ip_shutdown;
barebox_set_model("Somfy Animeo IP");
barebox_set_hostname("animeoip");
- at91_register_uart(3, 0);
return 0;
}
console_initcall(animeo_ip_console_init);
@@ -351,3 +368,64 @@ static int animeo_ip_main_clock(void)
return 0;
}
pure_initcall(animeo_ip_main_clock);
+
+static unsigned int get_char_timeout(struct console_device *cs, int timeout)
+{
+ uint64_t start = get_time_ns();
+
+ do {
+ if (!cs->tstc(cs))
+ continue;
+ return cs->getc(cs);
+ } while (!is_timeout(start, timeout));
+
+ return -1;
+}
+
+static int animeo_ip_cross_detect_init(void)
+{
+ struct console_device *cs0, *cs1;
+ int i;
+ char *s = "loop";
+ int crossed = 0;
+
+ cs0 = console_get_by_dev(usart0);
+ if (!cs0)
+ return -EINVAL;
+ cs1 = console_get_by_dev(usart1);
+ if (!cs1)
+ return -EINVAL;
+
+ at91_set_gpio_input(AT91_PIN_PC16, 0);
+ cs0->set_mode(cs0, CONSOLE_MODE_RS485);
+ cs0->setbrg(cs0, 38400);
+ cs1->set_mode(cs1, CONSOLE_MODE_RS485);
+ cs1->setbrg(cs1, 38400);
+
+ /* empty the bus */
+ while (cs1->tstc(cs1))
+ cs1->getc(cs1);
+
+ for (i = 0; i < strlen(s); i++) {
+ unsigned int ch = s[i];
+ unsigned int c;
+
+resend:
+ cs0->putc(cs0, ch);
+ c = get_char_timeout(cs1, 10 * MSECOND);
+ if (c == 0)
+ goto resend;
+ else if (c != ch)
+ goto err;
+ }
+
+ crossed = 1;
+
+err:
+ export_env_ull("rs485_crossed", crossed);
+
+ pr_info("rs485 ports %scrossed\n", crossed ? "" : "not ");
+
+ return 0;
+}
+late_initcall(animeo_ip_cross_detect_init);
diff --git a/arch/arm/configs/animeo_ip_defconfig b/arch/arm/configs/animeo_ip_defconfig
index 7f6961f..e076162 100644
--- a/arch/arm/configs/animeo_ip_defconfig
+++ b/arch/arm/configs/animeo_ip_defconfig
@@ -16,7 +16,6 @@ CONFIG_PROMPT_HUSH_PS2="y"
CONFIG_HUSH_FANCY_PROMPT=y
CONFIG_CMDLINE_EDITING=y
CONFIG_AUTO_COMPLETE=y
-CONFIG_CONSOLE_ACTIVATE_ALL=y
CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y
CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/animeo_ip/env"
CONFIG_CMD_EDIT=y
diff --git a/common/console_common.c b/common/console_common.c
index 5d2ccdb..cc184df 100644
--- a/common/console_common.c
+++ b/common/console_common.c
@@ -169,6 +169,19 @@ int fputc(int fd, char c)
}
EXPORT_SYMBOL(fputc);
+struct console_device *console_get_by_dev(struct device_d *dev)
+{
+ struct console_device *cdev;
+
+ for_each_console(cdev) {
+ if (cdev->dev == dev)
+ return cdev;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(console_get_by_dev);
+
/*
* @brief returns current used console device
*
diff --git a/common/startup.c b/common/startup.c
index 0a36c07..2e0a4ba 100644
--- a/common/startup.c
+++ b/common/startup.c
@@ -161,6 +161,8 @@ void __noreturn hang (void)
for (;;);
}
+void (*board_shutdown)(void);
+
/* Everything needed to cleanly shutdown barebox.
* Should be called before starting an OS to get
* the devices into a clean state
@@ -171,4 +173,6 @@ void shutdown_barebox(void)
#ifdef ARCH_SHUTDOWN
arch_shutdown();
#endif
+ if (board_shutdown)
+ board_shutdown();
}
diff --git a/drivers/serial/atmel.c b/drivers/serial/atmel.c
index 8392e78..c2a5d33 100644
--- a/drivers/serial/atmel.c
+++ b/drivers/serial/atmel.c
@@ -362,6 +362,32 @@ static int atmel_serial_setbaudrate(struct console_device *cdev, int baudrate)
return 0;
}
+static int atmel_serial_set_mode(struct console_device *cdev, enum console_mode mode)
+{
+ struct atmel_uart_port *uart = to_atmel_uart_port(cdev);
+ u32 mr;
+ u8 m;
+
+ mr = readl(uart->base + USART3_MR);
+ mr &= ~0xf;
+
+ switch (mode) {
+ case CONSOLE_MODE_NORMAL:
+ m = USART3_USART_MODE_NORMAL;
+ break;
+ case CONSOLE_MODE_RS485:
+ m = USART3_USART_MODE_RS485;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mr |= USART3_BF(USART_MODE, m);
+ writel(mr, uart->base + USART3_MR);
+
+ return 0;
+}
+
/*
* Initialise the serial port with the given baudrate. The settings
* are always 8 data bits, no parity, 1 stop bit, no start bits.
@@ -401,6 +427,7 @@ static int atmel_serial_probe(struct device_d *dev)
cdev->putc = atmel_serial_putc;
cdev->getc = atmel_serial_getc;
cdev->setbrg = atmel_serial_setbaudrate;
+ cdev->set_mode = atmel_serial_set_mode;
atmel_serial_init_port(cdev);
diff --git a/include/common.h b/include/common.h
index 066827f..0f0ba08 100644
--- a/include/common.h
+++ b/include/common.h
@@ -152,6 +152,7 @@ extern int (*barebox_main)(void);
void __noreturn start_barebox(void);
void shutdown_barebox(void);
+extern void (*board_shutdown)(void);
/*
* architectures which have special calling conventions for
diff --git a/include/console.h b/include/console.h
index d12a06e..550b440 100644
--- a/include/console.h
+++ b/include/console.h
@@ -28,6 +28,11 @@
#define CONSOLE_STDOUT (1 << 1)
#define CONSOLE_STDERR (1 << 2)
+enum console_mode {
+ CONSOLE_MODE_NORMAL,
+ CONSOLE_MODE_RS485,
+};
+
struct console_device {
struct device_d *dev;
struct device_d class_dev;
@@ -37,6 +42,7 @@ struct console_device {
int (*getc)(struct console_device *cdev);
int (*setbrg)(struct console_device *cdev, int baudrate);
void (*flush)(struct console_device *cdev);
+ int (*set_mode)(struct console_device *cdev, enum console_mode mode);
struct list_head list;
@@ -48,6 +54,8 @@ struct console_device {
int console_register(struct console_device *cdev);
int console_unregister(struct console_device *cdev);
+struct console_device *console_get_by_dev(struct device_d *dev);
+
extern struct list_head console_list;
#define for_each_console(console) list_for_each_entry(console, &console_list, list)