Run bootloader from application rt1062

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Run bootloader from application rt1062

Jump to solution
6,597 Views
Robert123
Contributor III

Hi,

I am using a Embedded Artists imx-rt1062-developers-kit with the following SDK: eaimxrt1062_sdk_2.8.6_freertos. I am trying to run the bootloader in ROM from an application.

The bootloader API tree and the following function is defined in bl_api.c

#define g_bootloaderTree (*(bootloader_api_entry_t**)(0x0020001c))

void bl_serial_downloader()
{
run_bootloader_ctx_t boot_para;
boot_para.B.imageIndex = 0;
boot_para.B.serialBootInterface = kEnterBootloader_SerialInterface_USB;
boot_para.B.bootMode = kEnterBootloader_Mode_SerialDownloader;
boot_para.B.tag = kEnterBootloader_Tag;
g_bootloaderTree->runBootloader((void *)&boot_para);
}

 

Since I am using FreeRTOS and I suspend all other tasks and disable the interrupts. This is how I call the bl_serial_downloader function:

vTaskSuspendAll();
taskDISABLE_INTERRUPTS();
bl_serial_downloader();

 

I have placed the bl_api and the following files in RAM and excluded them from the Flash memory. This is the “data.ldt” file:

<#if memory.name=="SRAM_ITC">
*mflash_drv.o(.text .text* .rodata .rodata*)
*fsl_flexspi.o(.text .text* .rodata .rodata*)
</#if>

<#if memory.name=="SRAM_OC">
*bl_api.o(.text .tVext* .rodata .rodata* .constdata .constdata.*)
*fsl_rtwdog.o(.text .tVext* .rodata .rodata* .constdata .constdata.*)
*fsl_wdog.o(.text .tVext* .rodata .rodata* .constdata .constdata.*)
</#if>

 

This is the Memory Layout:

memory id="RAM" size="1024" type="RAM"

memoryInstance derived_from="Flash" driver="MIMXRT1050-EcoXiP_ATXP032.cfx" edited="true" id="BOARD_FLASH" location="0x60000000" size="0x400000"

memoryInstance derived_from="RAM" edited="true" id="BOARD_SDRAM" location="0x80000000" size="0x1000000"

memoryInstance derived_from="RAM" edited="true" id="NCACHE_REGION" location="0x81e00000" size="0x1000000"

memoryInstance derived_from="RAM" edited="true" id="SRAM_DTC" location="0x20000000" size="0x20000"

memoryInstance derived_from="RAM" edited="true" id="SRAM_ITC" location="0x0" size="0x20000"

memoryInstance derived_from="RAM" edited="true" id="SRAM_OC" location="0x20200000" size="0xc0000"

When I try to flash with the Secure Provisioning Tool I get the following error:

20107 (0x4E8B) kStatus_FlexSPINOR_SFDP_NotFound

 

Here are the commands that Secure Provision Tool are trying to send:

$blhost -u 0x15A2,0x0073 -j -- get-property 1 0
blhost failed
FlashLoader is not running yet, download and run it
$sdphost -u 0x1FC9,0x0135 -j – error-status
sdphost succeeded, HAB disabled
$sdphost -u 0x1FC9,0x0135 -j -- write-file 0x20000000 /opt/nxp/MCUX_Provi_v2.1/bin/data/targets/MIMXRT1060/ivt_flashloader.bin
$sdphost -u 0x1FC9,0x0135 -j -- jump-address 0x20000400
$blhost -u 0x15A2,0x0073 -j -- get-property 1 0
$blhost -u 0x15A2,0x0073 -j -- fill-memory 0x2000 4 0xC0803007 word
$blhost -u 0x15A2,0x0073 -j -- fill-memory 0x2004 4 0x00000000 word
$blhost -u 0x15A2,0x0073 -j -- configure-memory 9 0x2000
blhost failed - 20107 (0x4E8B) kStatus_FlexSPINOR_SFDP_NotFound

 

Which are exatly the same commands that are send when I flash when I press the "ISP enable" button on the board.

 

I also tried the Flashloader SDK example and it gives the same error when I try to flash. From looking at the source code I suspects if fails in the following function:

status_t flexspi_nor_read_sfdp_info(uint32_t instance, jedec_info_table_t *tbl, bool address_shift_enable)
{
status_t status = kStatus_FlexSPINOR_SFDP_NotFound;
do
{
if (tbl == NULL)
{
status = kStatus_InvalidArgument;
break;
}

sfdp_header_t sfdp_header;
uint32_t address;

status = flexspi_nor_read_sfdp(instance, 0, (uint32_t *)&sfdp_header, sizeof(sfdp_header));

if (status != kStatus_Success)
{
break;
}

if (sfdp_header.signature != SFDP_SIGNATURE)
{
status = kStatus_FlexSPINOR_SFDP_NotFound;
break;
}

 

From looking at the code I am not sure how the SFDP signature is supposed to be read correctly.

I hope someone can help me. Thanks in advance.

/Robert

Labels (1)
Tags (2)
0 Kudos
1 Solution
6,327 Views
Robert123
Contributor III

Hi, I managed it to work now. I am not sure why it didn't work yesterday but maybe I forgot to run the application in RAM.

Here is the code (modified from the software_reset example) to reset the flexspi pins

 

/*
 * JEDEC reset of external serial flash in two steps:
 * 1) Disable interrupts and the data cache
 * 2) Do the JEDEC reset sequence
 *
 * Note: This function must be executing in RAM.
 * Note: Function call only valid for targets running in/from
 *       flash - not for targets running in debugger and/or in RAM
 */
RAMFUNCTION_SECTION_CODE(void flexspi_reset(void))
{
#define CS  (1<<6)
#define SCK (1<<7)
#define SI  (1<<8)
#define RESETMASK   (CS|SCK|SI)
#define IGNOREPINS  ((1<<9)|(1<<10)|(1<<11)|(1<<1)|(1<<2)|(1<<3))
#define LOW(__mask)   GPIO3->DR &= ~(__mask)  /* Set pin output to low level.*/
#define HIGH(__mask)  GPIO3->DR |=  (__mask)  /* Set pin output to high level.*/

    __disable_irq();
    SCB_DisableDCache();

    /* Configure CS/SCK/SI as outputs and the other flexspi pins as inputs */
    CLOCK_EnableClock(kCLOCK_Gpio3);
    GPIO3->IMR &= ~(RESETMASK | IGNOREPINS);
    GPIO3->GDIR |= (RESETMASK);
    GPIO3->GDIR &= ~(IGNOREPINS);

    IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_06_GPIO3_IO06,0);
    IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_07_GPIO3_IO07,0);
    IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_08_GPIO3_IO08,0);
    IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_09_GPIO3_IO09,0);
    IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_10_GPIO3_IO10,0);
    IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_11_GPIO3_IO11,0);
    IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_01_GPIO3_IO01,0);
    IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_02_GPIO3_IO02,0);
    IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_03_GPIO3_IO03,0);

    IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_06_GPIO3_IO06, 0x10b0);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_07_GPIO3_IO07, 0x10b0);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_08_GPIO3_IO08, 0x10b0);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_09_GPIO3_IO09, 0x10b0);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_10_GPIO3_IO10, 0x10b0);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_11_GPIO3_IO11, 0x10b0);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_01_GPIO3_IO01, 0x10b0);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_02_GPIO3_IO02, 0x10b0);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_03_GPIO3_IO03, 0x10b0);


    /* Reset sequence */
    HIGH(CS);
    LOW(SCK|SI);

    LOW(CS);
    HIGH(CS);
    HIGH(SI);

    LOW(CS);
    HIGH(CS);
    LOW(SI);

    LOW(CS);
    HIGH(CS);
    HIGH(SI);

    LOW(CS);
    HIGH(CS);

    /* Delay at least 110us */
    for (int i = 33000; i >= 0; i--) {
        __NOP();
    }
}

 

 

Thanks so much for the help

View solution in original post

0 Kudos
14 Replies
6,545 Views
Robert123
Contributor III

I have made a small example project from the iled_blinky SDK example and added a call to the ROM bootloader. I still have the same issue.

0 Kudos
6,529 Views
jeremyzhou
NXP Employee
NXP Employee

Hi,
Thanks for your sharing.
I port your code to the fsl_romapi and run the code demo on the MIMXRT1060 EVK board.
Actually, it can enter the serial downloader mode successfully (as the below figure shows), the attachment is my testing code.

2021-06-04_16-24-39.png
Have a great day,
TIC

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

 

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos
6,512 Views
Robert123
Contributor III

Hi, I upgraded the SDK version to 2.9.3 (from Embedded Artists http://imx.embeddedartists.com/). I have the following board: https://www.embeddedartists.com/products/imx-rt1062-developers-kit/

I still get the same error and it stops after:

 

/* Setup FLEXSPI NOR Configuration Block */
status = ROM_FLEXSPI_NorFlash_GetConfig(FlexSpiInstance, &norConfig, &option);

 

 And prints "Get FLEXSPI NOR configuration block failure" with status = 20107

I also tested the SDK example in 2.9.3 called "fsl_romapi" and it also cannot setup the FLEXSPI NOR Configuration Block.

I have tested both to flash with the Debugger (Segger J-link) and with the Secure Provision Tool (see attached picture)

 

0 Kudos
6,509 Views
jeremyzhou
NXP Employee
NXP Employee

Hi,
Thanks for your reply.
I've run the fsl_romapi on the MIMXRT1060 EVK board and it works well.
As we know, the onboard QSPI is different between the MIMXRT1060 EVK and Embedded Artists iMX RT1062 OEM board
Can you illustrate the difference of the fsl_romapi demo between the original and Embedded Artists's version? It may help me to figure it out.
Have a great day,
TIC

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

 

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos
6,503 Views
Robert123
Contributor III

Here is a git diff between the EAIMXRT1062 and the EVK-MIMXRT1060 for the fsl_rom_api SDK example, both are using SDK version 2.9.3. 

0 Kudos
6,482 Views
Robert123
Contributor III

Here is the ReadMe written by Embedded Artists found in the folder "doc". Which describes what has been patched by Embedded Artists from the original SDK example

0 Kudos
6,469 Views
jeremyzhou
NXP Employee
NXP Employee

Hi,
Thanks for your reply. In my opinion,
it's better to contact the Embedded Artists about the phenomenon too, they may give us new insights.
Have a great day,
TIC

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

 

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos
6,441 Views
Robert123
Contributor III

Hi,

I tried to update the LUT in the boot header but was unsuccessful.

According to the Adesto XIP datasheet (https://www.dialog-semiconductor.com/sites/default/files/2021-04/DS-ATXP032-114I-042020_0.pdf) the LUT command is 0x5A

According to table 9-16 in the IMXRT1060RM.pdf the Index for reading SFPD is 13 so I added

#define EXIP_CMD_READ_SFDP 0x5A // Read SFPD

[13] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, EXIP_CMD_READ_SFDP, RADDR_SDR, FLEXSPI_1PAD, 24)

to the boot header defined in evkmimxrt1060_flexspi_nor_config.c:

#define EXIP_CMD_READ_SFDP 0x5A // Read SFPD

#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
__attribute__((section(".boot_hdr.conf"), used))
#elif defined(__ICCARM__)
#pragma location = ".boot_hdr.conf"
#endif

const flexspi_nor_config_t qspiflash_config = {
    .memConfig =
    {
        .tag = FLEXSPI_CFG_BLK_TAG,
        .version = FLEXSPI_CFG_BLK_VERSION,
        .readSampleClksrc=kFlexSPIReadSampleClk_ExternalInputFromDqsPad,
        .csHoldTime = 3u,
        .csSetupTime = 3u,
        .columnAddressWidth = 0u,
        .deviceModeCfgEnable = 1,
        // Sequence for changing device mode. In this sequence we write to status/control regs 2-3.
        // This will switch EcoXiP to Octal-DDR mode and modify the number of dummy cycles used by it.
        .deviceModeSeq = {.seqId=14, .seqNum=1}, // index/size Status/Control Registers sequence
        .deviceModeArg = 0x88 | (CTRL_REG_BYTE3_VAL << 8), // values to be written to status/control regs 2-3
        // Enable DDR mode, Safe configuration
        .controllerMiscOption = (1u << kFlexSpiMiscOffset_DdrModeEnable) |
                                (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable),
        .deviceType = kFlexSpiDeviceType_SerialNOR, // serial NOR
        .sflashPadType = kSerialFlash_8Pads,
        .serialClkFreq = kFlexSpiSerialClk_133MHz,
        .lutCustomSeqEnable = 0, // Use pre-defined LUT sequence index and number
        .sflashA1Size = 4u * 1024u * 1024u,
        .dataValidTime = {[0] = 20}, //2ns from DQS to data
        .busyOffset = 0, // busy bit in bit 0
        .busyBitPolarity = 0, // busy bit is 1 when device is busy
        .lookupTable =
            {
                // Read
                [0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_8PAD, EXIP_CMD_READARRAY, RADDR_DDR, FLEXSPI_8PAD, 0x20),
                [1] = FLEXSPI_LUT_SEQ(DUMMY_DDR, FLEXSPI_8PAD,(ECOXIP_READ_NON_SPI_DUMMY_CYCLES*2+1), READ_DDR, FLEXSPI_8PAD, 0x80),
                // Read Status
                [4] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_8PAD, EXIP_CMD_READ_STATUS_REG_BYTE1, DUMMY_DDR, FLEXSPI_8PAD, 0x08),
                [5] = FLEXSPI_LUT_SEQ(READ_DDR, FLEXSPI_8PAD, 0x01, STOP, FLEXSPI_1PAD, 0x0),
                // Write Enable
                [12] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, EXIP_CMD_WRITE_ENABLE, STOP, FLEXSPI_1PAD, 0x0),
				// Read SFDP
				[13] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, EXIP_CMD_READ_SFDP, RADDR_SDR, FLEXSPI_1PAD, 24),

				// Write Status/Control Registers (this specifc sequence will writes 2 bytes to status/control regs 2-3)
                [56] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, EXIP_CMD_WRITE_STAT_CTRL_REGS, CMD_SDR, FLEXSPI_1PAD, 0x02),
                [57] = FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0x02, STOP, FLEXSPI_1PAD, 0x0),
            },
    },
    .pageSize = 256u,
    .sectorSize = 4096u, // 4K - that's actually a block not a sector (has to match erase size)
    .ipcmdSerialClkFreq = 1, // 30MHz
    .blockSize = 4096u,
    .isUniformBlockSize = true,
};
#endif /* XIP_BOOT_HEADER_ENABLE */

 

It will give the same error message as before.

For the Flashloader SDK example in function flexspi_nor_generate_config_block_adesto_octalflash, the function tries to update the LUT with the following sequence:

        // Read SFDP LUT sequence for 1 pad instruction
        { FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, kSerialFlash_ReadSFDP, RADDR_SDR, FLEXSPI_1PAD, 24),
          FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_1PAD, 8, READ_SDR, FLEXSPI_1PAD, 0xFF), 0, 0 },

with kSerialFlash_ReadSFDP = 0x5A

 

0 Kudos
6,402 Views
jeremyzhou
NXP Employee
NXP Employee

Hi,
Thanks for your reply.
After digging deeper, I guess the issue may be related to the non-initial status of the FlexSPI module and external Flash chip, as we know, during the boot-up, both FlexSPI and external Flash chip will be configured by the ROM code.
So you can try to reset them prior to calling bl_serial_downloader() function, there's a software_reset project in the latest patched SDK from here: http://imx.embeddedartists.com/#imxrt1062
for implementing the reset operation.
Please give it a try.
Have a great day,
TIC

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

 

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

6,371 Views
Robert123
Contributor III

Hi, have have tested to reset the flexspi pins (IOMUXC_SetPinMux and IOMUXC_SetPinConfig) before calling the bootloader but with no luck.

I have also tested reset the flexspi pins on the fsl_romapi example but it will give the same error message as before.

0 Kudos
6,333 Views
jeremyzhou
NXP Employee
NXP Employee

Hi,
Thanks for your reply.
I was wondering if you can share the complete demo code, as it can help me to figure it out.
Looking forward to your reply.
Have a great day,
TIC

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

 

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos
6,328 Views
Robert123
Contributor III

Hi, I managed it to work now. I am not sure why it didn't work yesterday but maybe I forgot to run the application in RAM.

Here is the code (modified from the software_reset example) to reset the flexspi pins

 

/*
 * JEDEC reset of external serial flash in two steps:
 * 1) Disable interrupts and the data cache
 * 2) Do the JEDEC reset sequence
 *
 * Note: This function must be executing in RAM.
 * Note: Function call only valid for targets running in/from
 *       flash - not for targets running in debugger and/or in RAM
 */
RAMFUNCTION_SECTION_CODE(void flexspi_reset(void))
{
#define CS  (1<<6)
#define SCK (1<<7)
#define SI  (1<<8)
#define RESETMASK   (CS|SCK|SI)
#define IGNOREPINS  ((1<<9)|(1<<10)|(1<<11)|(1<<1)|(1<<2)|(1<<3))
#define LOW(__mask)   GPIO3->DR &= ~(__mask)  /* Set pin output to low level.*/
#define HIGH(__mask)  GPIO3->DR |=  (__mask)  /* Set pin output to high level.*/

    __disable_irq();
    SCB_DisableDCache();

    /* Configure CS/SCK/SI as outputs and the other flexspi pins as inputs */
    CLOCK_EnableClock(kCLOCK_Gpio3);
    GPIO3->IMR &= ~(RESETMASK | IGNOREPINS);
    GPIO3->GDIR |= (RESETMASK);
    GPIO3->GDIR &= ~(IGNOREPINS);

    IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_06_GPIO3_IO06,0);
    IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_07_GPIO3_IO07,0);
    IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_08_GPIO3_IO08,0);
    IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_09_GPIO3_IO09,0);
    IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_10_GPIO3_IO10,0);
    IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_11_GPIO3_IO11,0);
    IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_01_GPIO3_IO01,0);
    IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_02_GPIO3_IO02,0);
    IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_03_GPIO3_IO03,0);

    IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_06_GPIO3_IO06, 0x10b0);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_07_GPIO3_IO07, 0x10b0);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_08_GPIO3_IO08, 0x10b0);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_09_GPIO3_IO09, 0x10b0);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_10_GPIO3_IO10, 0x10b0);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_11_GPIO3_IO11, 0x10b0);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_01_GPIO3_IO01, 0x10b0);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_02_GPIO3_IO02, 0x10b0);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_03_GPIO3_IO03, 0x10b0);


    /* Reset sequence */
    HIGH(CS);
    LOW(SCK|SI);

    LOW(CS);
    HIGH(CS);
    HIGH(SI);

    LOW(CS);
    HIGH(CS);
    LOW(SI);

    LOW(CS);
    HIGH(CS);
    HIGH(SI);

    LOW(CS);
    HIGH(CS);

    /* Delay at least 110us */
    for (int i = 33000; i >= 0; i--) {
        __NOP();
    }
}

 

 

Thanks so much for the help

0 Kudos
6,463 Views
Robert123
Contributor III

Hi, I have contacted Embedded Artists. Since the QSPI Flash is different from the original NXP development board the LUT for the memory needs to be updated/configured. I will mark this as complete and post an update later if I succeed with the LUT configuration.  

0 Kudos
6,582 Views
jeremyzhou
NXP Employee
NXP Employee

Hi,
Thank you for your interest in NXP Semiconductor products and for the opportunity to serve you.
I'll test later and inform you ASAP.
Have a great day,
TIC

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

 

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

 

0 Kudos