
Hi Michael,
Am Mo., 7. Sept. 2020 um 23:08 Uhr schrieb Michael Walle michael@walle.cc:
The board supports 16 configuration bits which can be manipulated with this command. See the board's README for a detailed explanation on each bit.
Signed-off-by: Michael Walle michael@walle.cc
Tested-by: Heiko Thiery heiko.thiery@gmail.com
board/kontron/sl28/Makefile | 2 +- board/kontron/sl28/cmds.c | 178 ++++++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 board/kontron/sl28/cmds.c
diff --git a/board/kontron/sl28/Makefile b/board/kontron/sl28/Makefile index 0f1866c874..74d8012f0f 100644 --- a/board/kontron/sl28/Makefile +++ b/board/kontron/sl28/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0+
ifndef CONFIG_SPL_BUILD -obj-y += sl28.o +obj-y += sl28.o cmds.o endif
obj-y += common.o ddr.o diff --git a/board/kontron/sl28/cmds.c b/board/kontron/sl28/cmds.c new file mode 100644 index 0000000000..046d3b4903 --- /dev/null +++ b/board/kontron/sl28/cmds.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- sl28 extension commands
- Copyright (c) 2020 Kontron Europe GmbH
- */
+#include <common.h> +#include <command.h> +#include <i2c.h> +#include <linux/delay.h>
+#define CPLD_I2C_ADDR 0x4a +#define REG_UFM_CTRL 0x02 +#define UFM_CTRL_DCLK BIT(1) +#define UFM_CTRL_DIN BIT(2) +#define UFM_CTRL_PROGRAM BIT(3) +#define UFM_CTRL_ERASE BIT(4) +#define UFM_CTRL_DSHIFT BIT(5) +#define UFM_CTRL_DOUT BIT(6) +#define UFM_CTRL_BUSY BIT(7)
+static int ufm_shift_data(struct udevice *dev, u16 data_in, u16 *data_out) +{
int i;
int ret;
u16 data = 0;
/* latch data */
ret = dm_i2c_reg_write(dev, REG_UFM_CTRL, 0);
if (ret < 0)
return ret;
ret = dm_i2c_reg_write(dev, REG_UFM_CTRL, UFM_CTRL_DCLK);
if (ret < 0)
return ret;
/* assert drshift */
ret = dm_i2c_reg_write(dev, REG_UFM_CTRL,
UFM_CTRL_DSHIFT | UFM_CTRL_DCLK);
if (ret < 0)
return ret;
/* clock 16 data bits, reverse order */
for (i = 15; i >= 0; i--) {
u8 din = (data_in & (1 << i)) ? UFM_CTRL_DIN : 0;
ret = dm_i2c_reg_write(dev, REG_UFM_CTRL, UFM_CTRL_DSHIFT
| din);
if (ret < 0)
return ret;
if (data_out) {
ret = dm_i2c_reg_read(dev, REG_UFM_CTRL);
if (ret < 0)
return ret;
if (ret & UFM_CTRL_DOUT)
data |= (1 << i);
}
ret = dm_i2c_reg_write(dev, REG_UFM_CTRL,
UFM_CTRL_DSHIFT | UFM_CTRL_DCLK | din);
if (ret < 0)
return ret;
}
/* deassert drshift */
ret = dm_i2c_reg_write(dev, REG_UFM_CTRL, UFM_CTRL_DCLK);
if (ret < 0)
return ret;
if (data_out)
*data_out = data;
return ret;
+}
+static int ufm_erase(struct udevice *dev) +{
int ret;
/* erase, tEPMX is 500ms */
ret = dm_i2c_reg_write(dev, REG_UFM_CTRL,
UFM_CTRL_DCLK | UFM_CTRL_ERASE);
if (ret < 0)
return ret;
ret = dm_i2c_reg_write(dev, REG_UFM_CTRL, UFM_CTRL_DCLK);
if (ret < 0)
return ret;
mdelay(500);
return 0;
+}
+static int ufm_program(struct udevice *dev) +{
int ret;
/* program, tPPMX is 100us */
ret = dm_i2c_reg_write(dev, REG_UFM_CTRL,
UFM_CTRL_DCLK | UFM_CTRL_PROGRAM);
if (ret < 0)
return ret;
ret = dm_i2c_reg_write(dev, REG_UFM_CTRL, UFM_CTRL_DCLK);
if (ret < 0)
return ret;
udelay(100);
return 0;
+}
+static int ufm_write(struct udevice *dev, u16 data) +{
int ret;
ret = ufm_shift_data(dev, data, NULL);
if (ret < 0)
return ret;
ret = ufm_erase(dev);
if (ret < 0)
return ret;
return ufm_program(dev);
+}
+static int ufm_read(struct udevice *dev, u16 *data) +{
return ufm_shift_data(dev, 0, data);
+}
+static int do_sl28_nvm(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
+{
struct udevice *dev;
u16 nvm;
int ret;
char *endp;
if (i2c_get_chip_for_busnum(0, CPLD_I2C_ADDR, 1, &dev))
return CMD_RET_FAILURE;
if (argc > 1) {
nvm = simple_strtoul(argv[1], &endp, 16);
if (*endp != '\0') {
printf("ERROR: argument is not a valid number\n");
ret = -EINVAL;
goto out;
}
/*
* We swap all bits, because the a zero bit in hardware means the
* feature is enabled. But this is hard for the user.
*/
nvm ^= 0xffff;
ret = ufm_write(dev, nvm);
if (ret)
goto out;
printf("New settings will be activated after the next power cycle!\n");
} else {
ret = ufm_read(dev, &nvm);
if (ret)
goto out;
nvm ^= 0xffff;
printf("%04hx\n", nvm);
}
return CMD_RET_SUCCESS;
+out:
printf("command failed (%d)\n", ret);
return CMD_RET_FAILURE;
+}
+static char sl28_help_text[] =
"nvm [<hex>] - display/set the 16 non-volatile bits\n";
+U_BOOT_CMD_WITH_SUBCMDS(sl28, "SMARC-sAL28 specific", sl28_help_text,
U_BOOT_SUBCMD_MKENT(nvm, 2, 1, do_sl28_nvm));