board/BuR/common: add br resetcontoller implementation

On many B&R boards we have a reset-controller, responsible for very
early board-bringup (voltages, clocks, ...) and bootmode selection.

To be ready for adding more B&R boards to source tree while avoiding
duplicate code, we add the resetcontroller implementation to the common
part of B&R boards.

Signed-off-by: Hannes Schmelzer <hannes.schmelzer@br-automation.com>
diff --git a/board/BuR/common/br_resetc.c b/board/BuR/common/br_resetc.c
new file mode 100644
index 0000000..190f141
--- /dev/null
+++ b/board/BuR/common/br_resetc.c
@@ -0,0 +1,234 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * common reset-controller functions for B&R boards
+ *
+ * Copyright (C) 2019 Hannes Schmelzer <oe5hpm@oevsv.at>
+ * B&R Industrial Automation GmbH - http://www.br-automation.com/ *
+ */
+#include <common.h>
+#include <errno.h>
+#include <i2c.h>
+#include <dm/uclass.h>
+#include "br_resetc.h"
+
+/* I2C Address of controller */
+#define	RSTCTRL_ADDR_PSOC	0x75
+#define	RSTCTRL_ADDR_STM32	0x60
+
+#define BMODE_DEFAULTAR		0
+#define BMODE_SERVICE		2
+#define BMODE_RUN		4
+#define BMODE_PME		12
+#define BMODE_DIAG		15
+
+#ifdef CONFIG_LCD
+#include <lcd.h>
+#define LCD_SETCURSOR(x, y)	lcd_position_cursor(x, y)
+#define LCD_PUTS(x)		lcd_puts(x)
+#else
+#define LCD_SETCURSOR(x, y)
+#define LCD_PUTS(x)
+#endif /* CONFIG_LCD */
+
+static const char *bootmodeascii[16] = {
+	"BOOT",		"reserved",	"reserved",	"reserved",
+	"RUN",		"reserved",	"reserved",	"reserved",
+	"reserved",	"reserved",	"reserved",	"reserved",
+	"PME",		"reserved",	"reserved",	"DIAG",
+};
+
+struct br_reset_t {
+	struct udevice *i2cdev;
+	u8 is_psoc;
+};
+
+static struct br_reset_t resetc;
+
+__weak int board_boot_key(void)
+{
+	return 0;
+}
+
+__weak void board_boot_led(unsigned int on)
+{
+}
+
+static int resetc_init(void)
+{
+	struct udevice *i2cbus;
+	int rc;
+
+	rc = uclass_get_device_by_seq(UCLASS_I2C, 0, &i2cbus);
+	if (rc) {
+		printf("Cannot find I2C bus #0!\n");
+		return -1;
+	}
+
+	rc = dm_i2c_probe(i2cbus,
+			  RSTCTRL_ADDR_PSOC, 0, &resetc.i2cdev);
+	if (rc) {
+		resetc.is_psoc = 0;
+		rc = dm_i2c_probe(i2cbus,
+				  RSTCTRL_ADDR_STM32, 0, &resetc.i2cdev);
+	}
+
+	if (rc)
+		printf("Warning: cannot probe BuR resetcontroller!\n");
+
+	return rc;
+}
+
+int br_resetc_regget(u8 reg, u8 *dst)
+{
+	int rc = 0;
+
+	if (!resetc.i2cdev)
+		rc = resetc_init();
+
+	if (rc != 0)
+		return rc;
+
+	return dm_i2c_read(resetc.i2cdev, reg, dst, 1);
+}
+
+int br_resetc_regset(u8 reg, u8 val)
+{
+	int rc = 0;
+	u16 regw = (val << 8) | val;
+
+	if (!resetc.i2cdev)
+		rc = resetc_init();
+
+	if (rc != 0)
+		return rc;
+
+	if (resetc.is_psoc)
+		return dm_i2c_write(resetc.i2cdev, reg, (u8 *)&regw, 2);
+
+	return dm_i2c_write(resetc.i2cdev, reg, (u8 *)&regw, 1);
+}
+
+int br_resetc_bmode(void)
+{
+	int rc = 0;
+	u16 regw;
+	u8 regb, scr;
+	int cnt;
+	unsigned int bmode = 0;
+
+	if (!resetc.i2cdev)
+		rc = resetc_init();
+
+	if (rc != 0)
+		return rc;
+
+	rc = dm_i2c_read(resetc.i2cdev, RSTCTRL_ENHSTATUS, &regb, 1);
+	if (rc != 0) {
+		printf("WARN: cannot read ENHSTATUS from resetcontroller!\n");
+		return -1;
+	}
+
+	rc = dm_i2c_read(resetc.i2cdev, RSTCTRL_SCRATCHREG0, &scr, 1);
+	if (rc != 0) {
+		printf("WARN: cannot read SCRATCHREG from resetcontroller!\n");
+		return -1;
+	}
+
+	board_boot_led(1);
+
+	/* special bootmode from resetcontroller */
+	if (regb & 0x4) {
+		bmode = BMODE_DIAG;
+	} else if (regb & 0x8) {
+		bmode = BMODE_DEFAULTAR;
+	} else if (board_boot_key() != 0) {
+		cnt = 4;
+		do {
+			LCD_SETCURSOR(1, 8);
+			switch (cnt) {
+			case 4:
+				LCD_PUTS
+				("release KEY to enter SERVICE-mode.     ");
+				break;
+			case 3:
+				LCD_PUTS
+				("release KEY to enter DIAGNOSE-mode.    ");
+				break;
+			case 2:
+				LCD_PUTS
+				("release KEY to enter BOOT-mode.        ");
+				break;
+			}
+			mdelay(1000);
+			cnt--;
+			if (board_boot_key() == 0)
+				break;
+		} while (cnt);
+
+		switch (cnt) {
+		case 0:
+			bmode = BMODE_PME;
+			break;
+		case 1:
+			bmode = BMODE_DEFAULTAR;
+			break;
+		case 2:
+			bmode = BMODE_DIAG;
+			break;
+		case 3:
+			bmode = BMODE_SERVICE;
+			break;
+		}
+	} else if ((regb & 0x1) || scr == 0xCC) {
+		bmode = BMODE_PME;
+	} else {
+		bmode = BMODE_RUN;
+	}
+
+	LCD_SETCURSOR(1, 8);
+
+	switch (bmode) {
+	case BMODE_PME:
+		LCD_PUTS("entering PME-Mode (netscript).         ");
+		regw = 0x0C0C;
+		break;
+	case BMODE_DEFAULTAR:
+		LCD_PUTS("entering BOOT-mode.                    ");
+		regw = 0x0000;
+		break;
+	case BMODE_DIAG:
+		LCD_PUTS("entering DIAGNOSE-mode.                ");
+		regw = 0x0F0F;
+		break;
+	case BMODE_SERVICE:
+		LCD_PUTS("entering SERVICE mode.                 ");
+		regw = 0xB4B4;
+		break;
+	case BMODE_RUN:
+		LCD_PUTS("loading OS...                          ");
+		regw = 0x0404;
+		break;
+	}
+
+	board_boot_led(0);
+
+	if (resetc.is_psoc)
+		rc = dm_i2c_write(resetc.i2cdev, RSTCTRL_SCRATCHREG0,
+				  (u8 *)&regw, 2);
+	else
+		rc = dm_i2c_write(resetc.i2cdev, RSTCTRL_SCRATCHREG0,
+				  (u8 *)&regw, 1);
+
+	if (rc != 0)
+		printf("WARN: cannot write into resetcontroller!\n");
+
+	if (resetc.is_psoc)
+		printf("Reset: PSOC controller\n");
+	else
+		printf("Reset: STM32 controller\n");
+
+	printf("Mode:  %s\n", bootmodeascii[regw & 0x0F]);
+	env_set_ulong("b_mode", regw & 0x0F);
+
+	return rc;
+}
diff --git a/board/BuR/common/br_resetc.h b/board/BuR/common/br_resetc.h
new file mode 100644
index 0000000..ba0689b
--- /dev/null
+++ b/board/BuR/common/br_resetc.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * common reset-controller functions for B&R boards
+ *
+ * Copyright (C) 2019 Hannes Schmelzer <oe5hpm@oevsv.at>
+ * B&R Industrial Automation GmbH - http://www.br-automation.com/ *
+ */
+#ifndef __CONFIG_BRRESETC_H__
+#define __CONFIG_BRRESETC_H__
+#include <common.h>
+
+int br_resetc_regget(u8 reg, u8 *dst);
+int br_resetc_regset(u8 reg, u8 val);
+int br_resetc_bmode(void);
+
+/* reset controller register defines */
+#define RSTCTRL_CTRLREG		0x01
+#define RSTCTRL_SCRATCHREG0	0x04
+#define RSTCTRL_ENHSTATUS	0x07
+#define RSTCTRL_SCRATCHREG1	0x08
+#define RSTCTRL_RSTCAUSE	0x00
+#define RSTCTRL_ERSTCAUSE	0x09
+#define RSTCTRL_SPECGPIO_I	0x0A
+#define RSTCTRL_SPECGPIO_O	0x0B
+
+#endif /* __CONFIG_BRRESETC_H__ */