| // 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 <env.h> |
| #include <errno.h> |
| #include <i2c.h> |
| #include <dm/uclass.h> |
| #include <linux/delay.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 |
| |
| #define LCD_SETCURSOR(x, y) |
| #define LCD_PUTS(x) |
| |
| 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; |
| } |
| |
| resetc.is_psoc = 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 *)®w, 2); |
| |
| return dm_i2c_write(resetc.i2cdev, reg, (u8 *)®w, 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, ®b, 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 *)®w, 2); |
| else |
| rc = dm_i2c_write(resetc.i2cdev, RSTCTRL_SCRATCHREG0, |
| (u8 *)®w, 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; |
| } |