uboot/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
   2/*
   3 * Copyright (C) 2020, STMicroelectronics - All Rights Reserved
   4 */
   5
   6#include <common.h>
   7#include <dfu.h>
   8#include <g_dnl.h>
   9#include <usb.h>
  10#include <asm/arch/stm32prog.h>
  11#include <asm/arch/sys_proto.h>
  12#include "stm32prog.h"
  13
  14static int stm32prog_set_phase(struct stm32prog_data *data, u8 phase,
  15                               u32 offset)
  16{
  17        struct stm32prog_part_t *part;
  18        int i;
  19
  20        if (phase == data->phase) {
  21                data->offset = offset;
  22                data->dfu_seq = 0;
  23                return 0;
  24        }
  25
  26        /* found partition for phase */
  27        for (i = 0; i < data->part_nb; i++) {
  28                part = &data->part_array[i];
  29                if (part->id == phase) {
  30                        data->cur_part = part;
  31                        data->phase = phase;
  32                        data->offset = offset;
  33                        data->dfu_seq = 0;
  34                        return 0;
  35                }
  36        }
  37
  38        return  -EINVAL;
  39}
  40
  41static int stm32prog_cmd_write(u64 offset, void *buf, long *len)
  42{
  43        u8 phase;
  44        u32 address;
  45        u8 *pt = buf;
  46        void (*entry)(void);
  47        int ret;
  48
  49        if (*len < 5) {
  50                pr_err("size not allowed\n");
  51                return  -EINVAL;
  52        }
  53        if (offset) {
  54                pr_err("invalid offset\n");
  55                return  -EINVAL;
  56        }
  57        phase = pt[0];
  58        address = (pt[1] << 24) | (pt[2] << 16) | (pt[3] << 8) | pt[4];
  59        if (phase == PHASE_RESET) {
  60                entry = (void *)address;
  61                printf("## Starting application at 0x%x ...\n", address);
  62                (*entry)();
  63                printf("## Application terminated\n");
  64                return 0;
  65        }
  66        /* set phase and offset */
  67        ret = stm32prog_set_phase(stm32prog_data, phase, address);
  68        if (ret)
  69                pr_err("failed: %d\n", ret);
  70        return ret;
  71}
  72
  73#define PHASE_MIN_SIZE  9
  74static int stm32prog_cmd_read(u64 offset, void *buf, long *len)
  75{
  76        u32 destination = DEFAULT_ADDRESS; /* destination address */
  77        u32 dfu_offset;
  78        u8 *pt_buf = buf;
  79        int phase;
  80        char *err_msg;
  81        int length;
  82
  83        if (*len < PHASE_MIN_SIZE) {
  84                pr_err("request exceeds allowed area\n");
  85                return  -EINVAL;
  86        }
  87        if (offset) {
  88                *len = 0; /* EOF for second request */
  89                return 0;
  90        }
  91        phase = stm32prog_data->phase;
  92        if (phase == PHASE_FLASHLAYOUT)
  93                destination = STM32_DDR_BASE;
  94        dfu_offset = stm32prog_data->offset;
  95
  96        /* mandatory header, size = PHASE_MIN_SIZE */
  97        *pt_buf++ = (u8)(phase & 0xFF);
  98        *pt_buf++ = (u8)(destination);
  99        *pt_buf++ = (u8)(destination >> 8);
 100        *pt_buf++ = (u8)(destination >> 16);
 101        *pt_buf++ = (u8)(destination >> 24);
 102        *pt_buf++ = (u8)(dfu_offset);
 103        *pt_buf++ = (u8)(dfu_offset >> 8);
 104        *pt_buf++ = (u8)(dfu_offset >> 16);
 105        *pt_buf++ = (u8)(dfu_offset >> 24);
 106
 107        if (phase == PHASE_RESET || phase == PHASE_DO_RESET) {
 108                err_msg = stm32prog_get_error(stm32prog_data);
 109                length = strlen(err_msg);
 110                if (length + PHASE_MIN_SIZE > *len)
 111                        length = *len - PHASE_MIN_SIZE;
 112
 113                memcpy(pt_buf, err_msg, length);
 114                *len = PHASE_MIN_SIZE + length;
 115                stm32prog_do_reset(stm32prog_data);
 116        } else if (phase == PHASE_FLASHLAYOUT) {
 117                *pt_buf++ = stm32prog_data->part_nb ? 1 : 0;
 118                *len = PHASE_MIN_SIZE + 1;
 119        } else {
 120                *len = PHASE_MIN_SIZE;
 121        }
 122
 123        return 0;
 124}
 125
 126int stm32prog_write_medium_virt(struct dfu_entity *dfu, u64 offset,
 127                                void *buf, long *len)
 128{
 129        if (dfu->dev_type != DFU_DEV_VIRT)
 130                return -EINVAL;
 131
 132        switch (dfu->data.virt.dev_num) {
 133        case PHASE_CMD:
 134                return stm32prog_cmd_write(offset, buf, len);
 135
 136        case PHASE_OTP:
 137                return stm32prog_otp_write(stm32prog_data, (u32)offset,
 138                                           buf, len);
 139
 140        case PHASE_PMIC:
 141                return stm32prog_pmic_write(stm32prog_data, (u32)offset,
 142                                            buf, len);
 143        }
 144        *len = 0;
 145        return 0;
 146}
 147
 148int stm32prog_read_medium_virt(struct dfu_entity *dfu, u64 offset,
 149                               void *buf, long *len)
 150{
 151        if (dfu->dev_type != DFU_DEV_VIRT)
 152                return -EINVAL;
 153
 154        switch (dfu->data.virt.dev_num) {
 155        case PHASE_CMD:
 156                return stm32prog_cmd_read(offset, buf, len);
 157
 158        case PHASE_OTP:
 159                return stm32prog_otp_read(stm32prog_data, (u32)offset,
 160                                          buf, len);
 161
 162        case PHASE_PMIC:
 163                return stm32prog_pmic_read(stm32prog_data, (u32)offset,
 164                                           buf, len);
 165        }
 166        *len = 0;
 167        return 0;
 168}
 169
 170int stm32prog_get_medium_size_virt(struct dfu_entity *dfu, u64 *size)
 171{
 172        if (dfu->dev_type != DFU_DEV_VIRT) {
 173                *size = 0;
 174                pr_debug("%s, invalid dev_type = %d\n",
 175                         __func__, dfu->dev_type);
 176                return -EINVAL;
 177        }
 178
 179        switch (dfu->data.virt.dev_num) {
 180        case PHASE_CMD:
 181                *size = 512;
 182                break;
 183        case PHASE_OTP:
 184                *size = OTP_SIZE;
 185                break;
 186        case PHASE_PMIC:
 187                *size = PMIC_SIZE;
 188                break;
 189        }
 190
 191        return 0;
 192}
 193
 194bool stm32prog_usb_loop(struct stm32prog_data *data, int dev)
 195{
 196        int ret;
 197        bool result;
 198        /* USB download gadget for STM32 Programmer */
 199        char product[128];
 200        char name[SOC_NAME_SIZE];
 201
 202        get_soc_name(name);
 203        snprintf(product, sizeof(product),
 204                 "USB download gadget@Device ID /0x%03X, @Revision ID /0x%04X, @Name /%s,",
 205                 get_cpu_dev(), get_cpu_rev(), name);
 206        g_dnl_set_product(product);
 207
 208        if (stm32prog_data->phase == PHASE_FLASHLAYOUT) {
 209                ret = run_usb_dnl_gadget(dev, "usb_dnl_dfu");
 210                if (ret || stm32prog_data->phase == PHASE_DO_RESET)
 211                        return ret;
 212                /* prepare the second enumeration with the FlashLayout */
 213                if (stm32prog_data->phase == PHASE_FLASHLAYOUT)
 214                        stm32prog_dfu_init(data);
 215                /* found next selected partition */
 216                stm32prog_next_phase(data);
 217        }
 218
 219        ret = run_usb_dnl_gadget(dev, "usb_dnl_dfu");
 220
 221        result = !!(ret) || (stm32prog_data->phase == PHASE_DO_RESET);
 222
 223        g_dnl_set_product(NULL);
 224
 225        return result;
 226}
 227
 228int g_dnl_get_board_bcd_device_number(int gcnum)
 229{
 230        pr_debug("%s\n", __func__);
 231        return 0x200;
 232}
 233