Add host(hackrf_info)/fw(usb_performance) IAP read part id/serial no(to be confirmed).

This commit is contained in:
TitanMKD
2013-03-09 11:47:28 +01:00
parent b77b0e82b6
commit 6620fe6ba9
8 changed files with 318 additions and 6 deletions

101
firmware/common/rom_iap.c Normal file
View File

@ -0,0 +1,101 @@
/*
* Copyright 2013 Benjamin Vernoux <titanmkd@gmail.com>
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "hackrf_core.h"
#include <stdint.h>
#include "rom_iap.h"
#define ROM_IAP_ADDR (0x10400100)
#define ROM_IAP_UNDEF_ADDR (0x12345678)
#define ROM_OTP_PART_ID_ADDR (0x40045000)
#define ROM_OTP_SERIAL_NO_ADDR (0x40045050) /* To be confirmed */
typedef void (* IAP_t)(uint32_t [],uint32_t[]);
typedef struct {
const IAP_t IAP; /* If equal to 0x12345678 IAP not implemented */
/* Other TBD */
} *pENTRY_ROM_API_t;
#define pROM_API ((pENTRY_ROM_API_t)ROM_IAP_ADDR)
/*
See Errata sheet ES_LPC43X0_A.pdf (LPC4350/30/20/10 Rev A)
3.5 IAP.1: In-Application Programming API not present on flashless parts
Introduction:
The LPC43x0 microcontrollers contain an APIfor In-Application Programming of flash
memory. This API also allows identification of the part.
Problem:
On the LPC43x0 microcontrollers, the IAP API is not present. The ISP interface is present
which allows the part to be identified externally (via the UART) but part identification is not
possible internally using the IAP call because it is not implemented.
The first word of the Part ID can be read directly from OTP at 0x40045000. The second word of the Part ID is always
'0' on flashless parts. */
bool iap_is_implemented(void)
{
bool res;
if( *((uint32_t*)ROM_IAP_ADDR) != ROM_IAP_UNDEF_ADDR )
{
res = true;
}else
{
res = false;
}
return res;
}
isp_iap_ret_code_t iap_cmd_call(iap_cmd_res_t* iap_cmd_res)
{
uint32_t* p_u32_data;
if( iap_is_implemented() )
{
pROM_API->IAP( (uint32_t*)&iap_cmd_res->cmd_param, (uint32_t*)&iap_cmd_res->status_res);
}else
{
/* Alternative way to retrieve Part Id & Serial No on MCU with no IAP */
switch(iap_cmd_res->cmd_param.command_code)
{
case IAP_CMD_READ_PART_ID_NO:
p_u32_data = (uint32_t*)ROM_OTP_PART_ID_ADDR;
iap_cmd_res->status_res.iap_result[0] = p_u32_data[0];
iap_cmd_res->status_res.iap_result[1] = p_u32_data[1];
iap_cmd_res->status_res.status_ret = CMD_SUCCESS;
break;
case IAP_CMD_READ_SERIAL_NO:
p_u32_data = (uint32_t*)ROM_OTP_SERIAL_NO_ADDR;
iap_cmd_res->status_res.iap_result[0] = p_u32_data[0];
iap_cmd_res->status_res.iap_result[1] = p_u32_data[1];
iap_cmd_res->status_res.iap_result[2] = p_u32_data[2];
iap_cmd_res->status_res.iap_result[3] = p_u32_data[3];
iap_cmd_res->status_res.status_ret = CMD_SUCCESS;
break;
default:
iap_cmd_res->status_res.status_ret = ERROR_IAP_NOT_IMPLEMENTED;
break;
}
}
return iap_cmd_res->status_res.status_ret;
}

121
firmware/common/rom_iap.h Normal file
View File

@ -0,0 +1,121 @@
/*
* Copyright 2013 Benjamin Vernoux <titanmkd@gmail.com>
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __ROM_IAP__
#define __ROM_IAP__
#include <stdint.h>
typedef enum
{
/* TODO define other commands */
IAP_CMD_INIT_IAP = 49,
/* Command Init IAP
Input Command code: 49 (decimal)
Return Code CMD_SUCCESS
Result None
Description Initializes and prepares the flash for erase and write operations.
Stack usage 88 B */
IAP_CMD_READ_PART_ID_NO = 54,
/* Read part identification number
Command Read part identification number
Input Command code: 54 (decimal)
Parameters:None
Return Code CMD_SUCCESS |
Result Result0:Part Identification Number.
Result1:Part Identification Number.
Description This command is used to read the part identification number. See Table 1082
LPC43xx part identification numbers.
The command returns two words: word0 followed by word1. Word 0 corresponds
to the part id and word1 indicates the flash configuration or contains 0x0 for
flashless parts.
Stack usage 8 B */
IAP_CMD_READ_SERIAL_NO = 58
/* Read device serial number
Input Command code: 58 (decimal)
Parameters: None
Return Code CMD_SUCCESS
Result Result0:First 32-bit word of Device Identification Number (at the lowest address)
Result1:Second 32-bit word of Device Identification Number
Result2:Third 32-bit word of Device Identification Number
Result3:Fourth 32-bit word of Device Identification Number
Description This command is used to read the device identification number. The serial number
may be used to uniquely identify a single unit among all LPC43xx devices.
Stack usage 8 B */
} iap_cmd_code_t;
/* ISP/IAP Return Code */
typedef enum
{
CMD_SUCCESS = 0x00000000, /* CMD_SUCCESS Command is executed successfully. Sent by ISP handler only when command given by the host has been completely and successfully executed. */
INVALID_COMMAND = 0x00000001, /* Invalid command. */
SRC_ADDR_ERROR = 0x00000002, /* Source address is not on word boundary. */
DST_ADDR_ERROR = 0x00000003, /* Destination address not on word or 256 byte boundary. */
SRC_ADDR_NOT_MAPPED = 0x00000004, /* Source address is not mapped in the memory map. Count value is taken into consideration where applicable. */
DST_ADDR_NOT_MAPPED = 0x00000005, /* Destination address is not mapped in the memory map. Count value is taken into consideration where applicable.*/
COUNT_ERROR = 0x00000006, /* Byte count is not multiple of 4 or is not a permitted value. */
INVALID_SECTOR = 0x00000007, /* Sector number is invalid or end sector number is greater than start sector number. */
SECTOR_NOT_BLANK = 0x00000008, /* Sector is not blank. */
SECTOR_NOT_PREP_WRITE_OP = 0x00000009, /* Command to prepare sector for write operation was not executed. */
COMPARE_ERROR = 0x0000000A, /* Source and destination data not equal. */
BUSY = 0x0000000B, /* Flash programming hardware interface is busy. */
PARAM_ERROR = 0x0000000C, /* Insufficient number of parameters or invalid parameter. */
ADDR_ERROR = 0x0000000D, /* Address is not on word boundary. */
ADDR_NOT_MAPPED = 0x0000000E, /* Address is not mapped in the memory map. Count value is taken in to consideration where applicable. */
CMD_LOCKED = 0x0000000F, /* Command is locked. */
INVALID_CODE = 0x00000010, /* Unlock code is invalid. */
INVALID_BAUD_RATE = 0x00000011, /* Invalid baud rate setting. */
INVALID_STOP_BIT = 0x00000012, /* Invalid stop bit setting. */
CODE_READ_PROTECTION_ENABLED = 0x00000013, /* Code read protection enabled. */
INVALID_FLASH_UNIT = 0x00000014, /* Invalid flash unit. */
USER_CODE_CHECKSUM = 0x00000015,
ERROR_SETTING_ACTIVE_PARTITION = 0x00000016,
/* Special Error */
ERROR_IAP_NOT_IMPLEMENTED = 0x00000100 /* IAP is not implemented in this part */
} isp_iap_ret_code_t;
typedef struct
{
/* Input Command/Param */
struct
{
iap_cmd_code_t command_code;
uint32_t iap_param[5];
} cmd_param;
/* Output Status/Result */
struct
{
isp_iap_ret_code_t status_ret;
uint32_t iap_result[4];
} status_res;
} iap_cmd_res_t;
/* Check if IAP is implemented */
bool iap_is_implemented(void);
isp_iap_ret_code_t iap_cmd_call(iap_cmd_res_t* iap_cmd_res);
#endif//__ROM_IAP__

View File

@ -38,6 +38,7 @@ SRC = $(BINARY).c \
../common/cpld_jtag.c \
../common/xapp058/lenval.c \
../common/xapp058/micro.c \
../common/xapp058/ports.c
../common/xapp058/ports.c \
../common/rom_iap.c
include ../common/Makefile_inc.mk

View File

@ -38,7 +38,8 @@ SRC = usb_performance.c \
../common/cpld_jtag.c \
../common/xapp058/lenval.c \
../common/xapp058/micro.c \
../common/xapp058/ports.c
../common/xapp058/ports.c \
../common/rom_iap.c
LDSCRIPT = ../common/LPC4330_M4_rom_to_ram.ld
include ../common/Makefile_inc.mk

View File

@ -34,6 +34,7 @@
#include <w25q80bv.h>
#include <cpld_jtag.h>
#include <sgpio.h>
#include <rom_iap.h>
#include "usb.h"
#include "usb_type.h"
@ -667,6 +668,47 @@ usb_request_status_t usb_vendor_request_set_amp_enable(
}
}
typedef struct {
uint32_t part_id[2];
uint32_t serial_no[4];
} read_partid_serialno_t;
usb_request_status_t usb_vendor_request_read_partid_serialno(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage)
{
uint8_t length;
read_partid_serialno_t read_partid_serialno;
iap_cmd_res_t iap_cmd_res;
if (stage == USB_TRANSFER_STAGE_SETUP)
{
/* Read IAP Part Number Identification */
iap_cmd_res.cmd_param.command_code = IAP_CMD_READ_PART_ID_NO;
iap_cmd_call(&iap_cmd_res);
if(iap_cmd_res.status_res.status_ret != CMD_SUCCESS)
return USB_REQUEST_STATUS_STALL;
read_partid_serialno.part_id[0] = iap_cmd_res.status_res.iap_result[0];
read_partid_serialno.part_id[1] = iap_cmd_res.status_res.iap_result[1];
/* Read IAP Serial Number Identification */
iap_cmd_res.cmd_param.command_code = IAP_CMD_READ_SERIAL_NO;
iap_cmd_call(&iap_cmd_res);
if(iap_cmd_res.status_res.status_ret != CMD_SUCCESS)
return USB_REQUEST_STATUS_STALL;
read_partid_serialno.serial_no[0] = iap_cmd_res.status_res.iap_result[0];
read_partid_serialno.serial_no[1] = iap_cmd_res.status_res.iap_result[1];
read_partid_serialno.serial_no[2] = iap_cmd_res.status_res.iap_result[2];
read_partid_serialno.serial_no[3] = iap_cmd_res.status_res.iap_result[3];
length = (uint8_t)sizeof(read_partid_serialno_t);
usb_endpoint_schedule(endpoint->in, &read_partid_serialno, length);
usb_endpoint_schedule_ack(endpoint->out);
}
return USB_REQUEST_STATUS_OK;
}
static const usb_request_handler_fn vendor_request_handler[] = {
NULL,
usb_vendor_request_set_transceiver_mode,
@ -685,7 +727,8 @@ static const usb_request_handler_fn vendor_request_handler[] = {
usb_vendor_request_read_board_id,
usb_vendor_request_read_version_string,
usb_vendor_request_set_freq,
usb_vendor_request_set_amp_enable
usb_vendor_request_set_amp_enable,
usb_vendor_request_read_partid_serialno
};
static const uint32_t vendor_request_handler_count =

View File

@ -32,6 +32,7 @@ int main(int argc, char** argv)
int result = HACKRF_SUCCESS;
uint8_t board_id = BOARD_ID_INVALID;
char version[255 + 1];
read_partid_serialno_t read_partid_serialno;
result = hackrf_init();
if (result != HACKRF_SUCCESS) {
@ -55,7 +56,6 @@ int main(int argc, char** argv)
hackrf_error_name(result), result);
return EXIT_FAILURE;
}
printf("Board ID Number: %d (%s)\n", board_id,
hackrf_board_id_name(board_id));
@ -65,9 +65,23 @@ int main(int argc, char** argv)
hackrf_error_name(result), result);
return EXIT_FAILURE;
}
printf("Firmware Version: %s\n", version);
result = hackrf_board_partid_serialno_read(device, &read_partid_serialno);
if (result != HACKRF_SUCCESS) {
fprintf(stderr, "hackrf_board_partid_serialno_read() failed: %s (%d)\n",
hackrf_error_name(result), result);
return EXIT_FAILURE;
}
printf("Part ID Number: 0x%08x 0x%08x\n",
read_partid_serialno.part_id[0],
read_partid_serialno.part_id[1]);
printf("Serial Number: 0x%08x 0x%08x 0x%08x 0x%08x\n",
read_partid_serialno.serial_no[0],
read_partid_serialno.serial_no[1],
read_partid_serialno.serial_no[2],
read_partid_serialno.serial_no[3]);
result = hackrf_close(device);
if (result != HACKRF_SUCCESS) {
fprintf(stderr, "hackrf_close() failed: %s (%d)\n",

View File

@ -46,7 +46,8 @@ typedef enum {
HACKRF_VENDOR_REQUEST_BOARD_ID_READ = 14,
HACKRF_VENDOR_REQUEST_VERSION_STRING_READ = 15,
HACKRF_VENDOR_REQUEST_SET_FREQ = 16,
HACKRF_VENDOR_REQUEST_AMP_ENABLE = 17
HACKRF_VENDOR_REQUEST_AMP_ENABLE = 17,
HACKRF_VENDOR_REQUEST_BOARD_PARTID_SERIALNO_READ = 18
} hackrf_vendor_request;
typedef enum {
@ -629,6 +630,29 @@ int hackrf_set_amp_enable(hackrf_device* device, const uint8_t value)
return HACKRF_SUCCESS;
}
}
int hackrf_board_partid_serialno_read(hackrf_device* device, read_partid_serialno_t* read_partid_serialno)
{
uint8_t length;
length = sizeof(read_partid_serialno_t);
int result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_BOARD_PARTID_SERIALNO_READ,
0,
0,
(unsigned char*)read_partid_serialno,
length,
0
);
if (result < length) {
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
static void* transfer_threadproc(void* arg) {
hackrf_device* device = (hackrf_device*)arg;

View File

@ -52,6 +52,11 @@ typedef struct {
int valid_length;
} hackrf_transfer;
typedef struct {
uint32_t part_id[2];
uint32_t serial_no[4];
} read_partid_serialno_t;
typedef int (*hackrf_sample_block_cb_fn)(hackrf_transfer* transfer);
int hackrf_init();
@ -97,6 +102,8 @@ int hackrf_set_freq(hackrf_device* device, const uint64_t freq_hz);
int hackrf_set_amp_enable(hackrf_device* device, const uint8_t value);
int hackrf_board_partid_serialno_read(hackrf_device* device, read_partid_serialno_t* read_partid_serialno);
const char* hackrf_error_name(enum hackrf_error errcode);
const char* hackrf_board_id_name(enum hackrf_board_id board_id);