Hi Michael, Am Mo., 7. Sept. 2020 um 23:08 Uhr schrieb Michael Walle <[email protected]>: > > 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 <[email protected]>
Tested-by: Heiko Thiery <[email protected]> > --- > 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)); -- Heiko

