[PATCH v7 2/2] board: sl28: add board specific nvm command

Heiko Thiery heiko.thiery at gmail.com
Mon Sep 14 13:02:57 CEST 2020


Hi Michael,

Am Mo., 7. Sept. 2020 um 23:08 Uhr schrieb Michael Walle <michael at 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 at walle.cc>

Tested-by: Heiko Thiery <heiko.thiery at 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));


-- 
Heiko


More information about the U-Boot mailing list