uboot/board/gardena/smart-gateway-mt7688/board.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2018 Stefan Roese <sr@denx.de>
   4 */
   5
   6#include <common.h>
   7#include <command.h>
   8#include <env.h>
   9#include <env_internal.h>
  10#include <init.h>
  11#include <led.h>
  12#include <log.h>
  13#include <malloc.h>
  14#include <net.h>
  15#include <spi.h>
  16#include <spi_flash.h>
  17#include <linux/delay.h>
  18#include <linux/stringify.h>
  19#include <u-boot/crc.h>
  20#include <uuid.h>
  21#include <linux/ctype.h>
  22#include <linux/io.h>
  23
  24#define MT76XX_AGPIO_CFG        0x1000003c
  25
  26#define FACTORY_DATA_OFFS       0xc0000
  27#define FACTORY_DATA_SECT_SIZE  0x10000
  28#if ((CONFIG_ENV_OFFSET_REDUND + CONFIG_ENV_SIZE) > FACTORY_DATA_OFFS)
  29#error "U-Boot image with environment too big (overlapping with factory-data)!"
  30#endif
  31#define FACTORY_DATA_USER_OFFS  0x140
  32#define FACTORY_DATA_SIZE       0x1f0
  33#define FACTORY_DATA_CRC_LEN    (FACTORY_DATA_SIZE -                    \
  34                                 FACTORY_DATA_USER_OFFS - sizeof(u32))
  35
  36#define FACTORY_DATA_MAGIC      0xCAFEBABE
  37
  38struct factory_data_values {
  39        u8 pad_1[4];
  40        u8 wifi_mac[6];         /* offs: 0x004: binary value */
  41        u8 pad_2[30];
  42        u8 eth_mac[6];          /* offs: 0x028: binary value */
  43        u8 pad_3[FACTORY_DATA_USER_OFFS - 4 - 6 - 30 - 6];
  44        /* User values start here at offset 0x140 */
  45        u32 crc;
  46        u32 magic;
  47        u32 version;
  48        char ipr_id[UUID_STR_LEN];      /* UUID as string w/o ending \0 */
  49        char hqv_id[UUID_STR_LEN];      /* UUID as string w/o ending \0 */
  50        char unielec_id[UUID_STR_LEN];  /* UUID as string w/o ending \0 */
  51};
  52
  53int board_early_init_f(void)
  54{
  55        void __iomem *gpio_mode;
  56
  57        /* Configure digital vs analog GPIOs */
  58        gpio_mode = ioremap_nocache(MT76XX_AGPIO_CFG, 0x100);
  59        iowrite32(0x00fe01ff, gpio_mode);
  60
  61        return 0;
  62}
  63
  64static bool prepare_uuid_var(const char *fd_ptr, const char *env_var_name,
  65                             char errorchar)
  66{
  67        char str[UUID_STR_LEN + 1] = { 0 };     /* Enough for UUID stuff */
  68        bool env_updated = false;
  69        char *env;
  70        int i;
  71
  72        memcpy(str, fd_ptr, UUID_STR_LEN);
  73
  74        /* Convert non-ascii character to 'X' */
  75        for (i = 0; i < UUID_STR_LEN; i++) {
  76                if (!(isascii(str[i]) && isprint(str[i])))
  77                        str[i] = errorchar;
  78        }
  79
  80        env = env_get(env_var_name);
  81        if (strcmp(env, str)) {
  82                env_set(env_var_name, str);
  83                env_updated = true;
  84        }
  85
  86        return env_updated;
  87}
  88
  89static void factory_data_env_config(void)
  90{
  91        struct factory_data_values *fd;
  92        struct spi_flash *sf;
  93        int env_updated = 0;
  94        char str[UUID_STR_LEN + 1];     /* Enough for UUID stuff */
  95        char *env;
  96        u8 *buf;
  97        u32 crc;
  98        int ret;
  99        u8 *ptr;
 100
 101        buf = malloc(FACTORY_DATA_SIZE);
 102        if (!buf) {
 103                printf("F-Data:Unable to allocate buffer\n");
 104                return;
 105        }
 106
 107        /*
 108         * Get values from factory-data area in SPI NOR
 109         */
 110        sf = spi_flash_probe(CONFIG_SF_DEFAULT_BUS,
 111                             CONFIG_SF_DEFAULT_CS,
 112                             CONFIG_SF_DEFAULT_SPEED,
 113                             CONFIG_SF_DEFAULT_MODE);
 114        if (!sf) {
 115                printf("F-Data:Unable to access SPI NOR flash\n");
 116                goto err_free;
 117        }
 118
 119        ret = spi_flash_read(sf, FACTORY_DATA_OFFS, FACTORY_DATA_SIZE,
 120                             (void *)buf);
 121        if (ret) {
 122                printf("F-Data:Unable to read factory-data from SPI NOR\n");
 123                goto err_spi_flash;
 124        }
 125
 126        fd = (struct factory_data_values *)buf;
 127
 128        if (fd->magic != FACTORY_DATA_MAGIC)
 129                printf("F-Data:Magic value not correct\n");
 130
 131        crc = crc32(0, (u8 *)&fd->magic, FACTORY_DATA_CRC_LEN);
 132        if (crc != fd->crc)
 133                printf("F-Data:CRC not correct\n");
 134        else
 135                printf("F-Data:factory-data version %x detected\n",
 136                       fd->version);
 137
 138        /* Handle wifi_mac env variable */
 139        ptr = fd->wifi_mac;
 140        sprintf(str, "%pM", ptr);
 141        if (!is_valid_ethaddr(ptr))
 142                printf("F-Data:Invalid MAC addr: wifi_mac %s\n", str);
 143
 144        env = env_get("wifiaddr");
 145        if (strcmp(env, str)) {
 146                env_set("wifiaddr", str);
 147                env_updated = 1;
 148        }
 149
 150        /* Handle eth_mac env variable */
 151        ptr = fd->eth_mac;
 152        sprintf(str, "%pM", ptr);
 153        if (!is_valid_ethaddr(ptr))
 154                printf("F-Data:Invalid MAC addr: eth_mac %s\n", str);
 155
 156        env = env_get("ethaddr");
 157        if (strcmp(env, str)) {
 158                env_set("ethaddr", str);
 159                env_updated = 1;
 160        }
 161
 162        /* Handle UUID env variables */
 163        env_updated |= prepare_uuid_var(fd->ipr_id, "linuxmoduleid", 'X');
 164        env_updated |= prepare_uuid_var(fd->hqv_id, "linuxmodulehqvid", '\0');
 165        env_updated |= prepare_uuid_var(fd->unielec_id,
 166                                        "linuxmoduleunielecid", '\0');
 167
 168        /* Check if the environment was updated and needs to get stored */
 169        if (env_updated != 0) {
 170                printf("F-Data:Values don't match env values -> saving\n");
 171                env_save();
 172        } else {
 173                debug("F-Data:Values match current env values\n");
 174        }
 175
 176err_spi_flash:
 177        spi_flash_free(sf);
 178
 179err_free:
 180        free(buf);
 181}
 182
 183int board_late_init(void)
 184{
 185        factory_data_env_config();
 186
 187        return 0;
 188}
 189
 190static void copy_or_generate_uuid(char *fd_ptr, const char *env_var_name)
 191{
 192        char str[UUID_STR_LEN + 1] = { 0 };     /* Enough for UUID stuff */
 193        char *env;
 194
 195        /* Don't use the UUID dest place, as the \0 char won't fit */
 196        env = env_get(env_var_name);
 197        if (env)
 198                strncpy(str, env, UUID_STR_LEN);
 199        else
 200                gen_rand_uuid_str(str, UUID_STR_FORMAT_STD);
 201
 202        memcpy(fd_ptr, str, UUID_STR_LEN);
 203}
 204
 205/*
 206 * Helper function to provide some sane factory-data values for testing
 207 * purpose, when these values are not programmed correctly
 208 */
 209int do_fd_write(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 210{
 211        struct factory_data_values *fd;
 212        struct spi_flash *sf;
 213        u8 *buf;
 214        int ret = CMD_RET_FAILURE;
 215
 216        buf = malloc(FACTORY_DATA_SECT_SIZE);
 217        if (!buf) {
 218                printf("F-Data:Unable to allocate buffer\n");
 219                return CMD_RET_FAILURE;
 220        }
 221
 222        sf = spi_flash_probe(CONFIG_SF_DEFAULT_BUS,
 223                             CONFIG_SF_DEFAULT_CS,
 224                             CONFIG_SF_DEFAULT_SPEED,
 225                             CONFIG_SF_DEFAULT_MODE);
 226        if (!sf) {
 227                printf("F-Data:Unable to access SPI NOR flash\n");
 228                goto err_free;
 229        }
 230
 231        /* Generate the factory-data struct */
 232
 233        /* Fist read complete sector into buffer */
 234        ret = spi_flash_read(sf, FACTORY_DATA_OFFS, FACTORY_DATA_SECT_SIZE,
 235                             (void *)buf);
 236        if (ret) {
 237                printf("F-Data:spi_flash_read failed (%d)\n", ret);
 238                goto err_spi_flash;
 239        }
 240
 241        fd = (struct factory_data_values *)buf;
 242        fd->magic = FACTORY_DATA_MAGIC;
 243        fd->version = 0x1;
 244
 245        /* Use existing MAC and UUID values or generate some random ones */
 246        if (!eth_env_get_enetaddr("wifiaddr", fd->wifi_mac)) {
 247                net_random_ethaddr(fd->wifi_mac);
 248                /* to get a different seed value for the MAC address */
 249                mdelay(10);
 250        }
 251
 252        if (!eth_env_get_enetaddr("ethaddr", fd->eth_mac))
 253                net_random_ethaddr(fd->eth_mac);
 254
 255        copy_or_generate_uuid(fd->ipr_id, "linuxmoduleid");
 256        copy_or_generate_uuid(fd->hqv_id, "linuxmodulehqvid");
 257        copy_or_generate_uuid(fd->unielec_id, "linuxmoduleunielecid");
 258
 259        printf("New factory-data values:\n");
 260        printf("wifiaddr=%pM\n", fd->wifi_mac);
 261        printf("ethaddr=%pM\n", fd->eth_mac);
 262
 263        /*
 264         * We don't have the \0 char at the end, so we need to specify the
 265         * length in the printf format instead
 266         */
 267        printf("linuxmoduleid=%." __stringify(UUID_STR_LEN) "s\n", fd->ipr_id);
 268        printf("linuxmodulehqvid=%." __stringify(UUID_STR_LEN) "s\n",
 269               fd->hqv_id);
 270        printf("linuxmoduleunielecid=%." __stringify(UUID_STR_LEN) "s\n",
 271               fd->unielec_id);
 272
 273        fd->crc = crc32(0, (u8 *)&fd->magic, FACTORY_DATA_CRC_LEN);
 274
 275        ret = spi_flash_erase(sf, FACTORY_DATA_OFFS, FACTORY_DATA_SECT_SIZE);
 276        if (ret) {
 277                printf("F-Data:spi_flash_erase failed (%d)\n", ret);
 278                goto err_spi_flash;
 279        }
 280
 281        ret = spi_flash_write(sf, FACTORY_DATA_OFFS, FACTORY_DATA_SECT_SIZE,
 282                              buf);
 283        if (ret) {
 284                printf("F-Data:spi_flash_write failed (%d)\n", ret);
 285                goto err_spi_flash;
 286        }
 287
 288        printf("F-Data:factory-data values written to SPI NOR flash\n");
 289
 290err_spi_flash:
 291        spi_flash_free(sf);
 292
 293err_free:
 294        free(buf);
 295
 296        return ret;
 297}
 298
 299#ifndef CONFIG_SPL_BUILD
 300U_BOOT_CMD(
 301        fd_write,       1,      0,      do_fd_write,
 302        "Write test factory-data values to SPI NOR",
 303        "\n"
 304);
 305#endif
 306