/*  *********************************************************************
    *  ASTRIS - Remote JTAG probe
    *
    *  Cypress Flasher Classes         File: astris_cyflash.h
    *
    *  This module handles some flashing MCUs from Cypress.
    *
    *********************************************************************
    *
    *  Copyright (C) 2016-2016  Apple, Inc. All rights reserved.
    *
    *  This document is the property of Apple Inc.
    *  It is considered confidential and proprietary.
    *
    *  This document may not be reproduced or transmitted in any form,
    *  in whole or in part, without the express written permission of
    *  Apple Inc.
    *********************************************************************
    * The base class is based on flashing technique used to flash CY8C42xx Parts
    * Doc: CY8C42xx programming procedure (Document No. 001-81799 Rev C)
    * The CypressFlasher_4100S class is for PSoC 4100S
    * Doc: PSoC4100S programming procedure (Document No. 001-95190 Rev D)
    * The CypressFlasher_CCG2 class is for CCG2 Flashing.
    * Doc: CYPD1xxx, CYPD2xxx Programming SpecificationsDoc. No. 001-96533 Rev.
*/

#ifndef _ASTRIS_CYFLASH_H
#define _ASTRIS_CYFLASH_H

// CY8C42xx
class CypressFlasher {
public:
    CypressFlasher(AXconn_t *conn, AXap_t *ap);
    virtual ~CypressFlasher();

    virtual int acquire_chip();
    virtual int erase_all_flash();
    virtual int reflash(void *buffer, size_t buff_size, bool eraseall);

protected:
    static const char *axl;

    AXconn_t *m_conn;
    AXap_t *m_ap;

    // System Request Register (0x40000004)
    AXmemaddr_t CPUSS_SYSREQ;
    const AXmemaddr_t CPUSS_SYSREQ_DEFAULT = 0x40000004;

    // System Request Argument Register (0x40000008)
    AXmemaddr_t CPUSS_SYSARG;
    const AXmemaddr_t CPUSS_SYSARG_DEFAULT = 0x40000008;

    // Test Mode Control Register
    const AXmemaddr_t TEST_MODE = 0x40030014;
    // SRAM address where parameters for SROM requests will be stored.
    const AXmemaddr_t SRAM_PARAMS_BASE = 0x20000100;
    // Location of flash protection settings in flash macro.
    const AXmemaddr_t SFLASH_MACRO = 0x0FFFF000;
    // Location of Chip Level Protection in flash macro (actual byte located at 0x0FFFF07F, but must read whole 32-bit word).
    const AXmemaddr_t SFLASH_CPUSS_PROTECTION = 0x0FFFF07C;

    //0x20000400
    AXmemaddr_t SRAM_INFINITE_LOOP_ADDR;
    AXmemaddr_t SRAM_INFINITE_LOOP_ADDR_DEFAULT = 0x20000400;

    const AXmemaddr_t SRAM_TOP_DEVICE_ADDRESS = 0x20001000;

    // SROM Requests Commands
    const uint32_t SROM_CMD_GET_SILICON_ID   = 0x00;
    const uint32_t SROM_CMD_LOAD_LATCH       = 0x04;
    const uint32_t SROM_CMD_PROGRAM_ROW      = 0x06;
    const uint32_t SROM_CMD_ERASE_ALL        = 0x0A;
    const uint32_t SROM_CMD_CHECKSUM         = 0x0B;
    const uint32_t SROM_CMD_WRITE_PROTECTION = 0x0D;

    // SROM Constants
    // Parameter of SROM call.
    const uint32_t SROM_KEY1 = 0xB6;
    // Parameter of SROM call.
    const uint32_t SROM_KEY2 = 0xD3;
    // Mask of SYSREQ bit in CPUSS_SYSREQ register. It starts execution of SROM command.
    const uint32_t SROM_SYSREQ_BIT = 0x80000000;
    // Mask of PRIVILIGED bit in CPUSS_SYSREQ register. Indicates whether system is in privileged mode (SROM command running) or user mode.
    const uint32_t SROM_PRIVILEGED_BIT = 0x10000000;
    // Successful status of system request (SROM command).
    const uint32_t SROM_STATUS_SUCCEEDED = 0xA0000000;
    // Fail status of system request (SROM command).
    const uint32_t SROM_STATUS_FAILED = 0xF0000000;

    const uint32_t CHIP_PROT_PROTECTED = 0x02;

    // Flash is either 16KB or 32KB
    // The programming is done in rows size of 128 Bytes
    // 256 rows max
    uint32_t ROW_SIZE;
    const uint32_t ROW_SIZE_DEFAULT = 128;

    uint32_t FLASH_SIZE = 32768;

    // ARM32 AIRCR Address
    const AXmemaddr_t R_AIRCR = 0xE000ED0C;

    // Program One Row
    virtual int program_row(void *src, size_t row_size, uint32_t row_id, uint32_t width = 4);

    // Poll Rom Status After Issuing Request
    virtual bool poll_srom_status();

    // Read Chip ID
    virtual uint32_t read_chip_id();

    virtual int read_system_request(uint32_t *reg_val);
    virtual int write_system_request(uint32_t reg_val);

    virtual int read_system_argument(uint32_t *reg_val);
    virtual int write_system_argument(uint32_t reg_val);

};

/// PSoC4100S
class CypressFlasher_4100S:
    public CypressFlasher {

public:
    CypressFlasher_4100S(AXconn_t *conn, AXap_t *ap);
    virtual int acquire_chip();

protected:
    static const char *axl;

    const AXmemaddr_t CPUSS_SYSREQ_OVERRIDE = 0x40100004;
    const AXmemaddr_t CPUSS_SYSARG_OVERRIDE = 0x40100008;

    const uint32_t SROM_CMD_SET_IMO_48_MHz = 0x15;
    const uint32_t FLASH_SIZE_OVERRIDE     = 65536;

    virtual int clock_to_48mhz();

};

/// CypressCCG
class CypressFlasher_CCG2:
    public CypressFlasher {

public:
    CypressFlasher_CCG2(AXconn_t *conn, AXap_t *ap);
    virtual int acquire_chip();
    virtual int erase_all_flash();

protected:
    static const char *axl;
    const AXmemaddr_t CPUSS_SYSREQ_OVERRIDE            = 0x40100004;
    const AXmemaddr_t CPUSS_SYSARG_OVERRIDE            = 0x40100008;
    const AXmemaddr_t SRAM_INFINITE_LOOP_ADDR_OVERRIDE = 0x20000300;

    const uint32_t SROM_CMD_SET_IMO_48_MHz = 0x15;

    virtual int clock_to_48mhz();
    virtual int reacquire_chip();

};

/// CypressCCG3
class CypressFlasher_CCG3:
    public CypressFlasher_CCG2 {

public:
    CypressFlasher_CCG3(AXconn_t *conn, AXap_t *ap);
    virtual int acquire_chip();

protected:
    static const char *axl;
    const uint32_t FLASH_SIZE_OVERRIDE = 131072; //128K
    const uint32_t ROW_SIZE_OVERRIDE   = 128;    //64B
    uint32_t ROWS_PER_MACRO            = 512;

    virtual int program_row(void *src, size_t row_size, uint32_t row_id, uint32_t width = 4);

};

/// Cypress4200L
class CypressFlasher_4200L:
    public CypressFlasher_CCG2 {

public:
    CypressFlasher_4200L(AXconn_t *conn, AXap_t *ap);
    virtual int acquire_chip();

protected:
    static const char *axl;
    const uint32_t FLASH_SIZE_OVERRIDE = 262144; //256K
    const uint32_t ROW_SIZE_OVERRIDE   = 256;    //256B
    uint32_t ROWS_PER_MACRO            = 512;

    virtual int program_row(void *src, size_t row_size, uint32_t row_id, uint32_t width = 4);
    virtual int reacquire_chip();

};

/// CypressS1
class CypressFlasher_S1:
    public CypressFlasher_CCG2 {

public:
    CypressFlasher_S1(AXconn_t *conn, AXap_t *ap);
    virtual int acquire_chip();

protected:
    static const char *axl;
    const uint32_t FLASH_SIZE_OVERRIDE = 131072; //128K
    const uint32_t ROW_SIZE_OVERRIDE   = 256;    //256
    uint32_t ROWS_PER_MACRO            = 512;

    virtual int program_row(void *src, size_t row_size, uint32_t row_id, uint32_t width = 4);

};

#endif // ifndef _ASTRIS_CYFLASH_H
