/***************************************************************************** (c) Cambridge Silicon Radio Limited 2011 All rights reserved and confidential information of CSR Refer to LICENSE.txt included with this source for details on the license terms. *****************************************************************************/ #ifndef CSR_WIFI_HIP_CHIPHELPER_H__ #define CSR_WIFI_HIP_CHIPHELPER_H__ #include /* The age of the BlueCore chip. This is probably not useful, if you know the age then you can probably work out the version directly. */ enum chip_helper_bluecore_age { chip_helper_bluecore_pre_bc7, chip_helper_bluecore_bc7_or_later }; /* We support up to three windowed regions at the moment. Don't reorder these - they're used to index into an array. */ enum chip_helper_window_index { CHIP_HELPER_WINDOW_1 = 0, CHIP_HELPER_WINDOW_2 = 1, CHIP_HELPER_WINDOW_3 = 2, CHIP_HELPER_WINDOW_COUNT = 3 }; /* These are the things that we can access through a window. Don't reorder these - they're used to index into an array. */ enum chip_helper_window_type { CHIP_HELPER_WT_CODE_RAM = 0, CHIP_HELPER_WT_FLASH = 1, CHIP_HELPER_WT_EXT_SRAM = 2, CHIP_HELPER_WT_ROM = 3, CHIP_HELPER_WT_SHARED = 4, CHIP_HELPER_WT_COUNT = 5 }; /* Commands to stop and start the XAP */ enum chip_helper_dbg_emu_cmd_enum { CHIP_HELPER_DBG_EMU_CMD_XAP_STEP_MASK = 0x0001, CHIP_HELPER_DBG_EMU_CMD_XAP_RUN_B_MASK = 0x0002, CHIP_HELPER_DBG_EMU_CMD_XAP_BRK_MASK = 0x0004, CHIP_HELPER_DBG_EMU_CMD_XAP_WAKEUP_MASK = 0x0008 }; /* Bitmasks for Stop and sleep status: DBG_SPI_STOP_STATUS & DBG_HOST_STOP_STATUS */ enum chip_helper_dbg_stop_status_enum { CHIP_HELPER_DBG_STOP_STATUS_NONE_MASK = 0x0000, CHIP_HELPER_DBG_STOP_STATUS_P0_MASK = 0x0001, CHIP_HELPER_DBG_STOP_STATUS_P1_MASK = 0x0002, CHIP_HELPER_DBG_STOP_STATUS_P2_MASK = 0x0004, CHIP_HELPER_DBG_STOP_STATUS_SLEEP_STATUS_P0_MASK = 0x0008, CHIP_HELPER_DBG_STOP_STATUS_SLEEP_STATUS_P1_MASK = 0x0010, CHIP_HELPER_DBG_STOP_STATUS_SLEEP_STATUS_P2_MASK = 0x0020, /* Legacy names/alias */ CHIP_HELPER_DBG_STOP_STATUS_MAC_MASK = 0x0001, CHIP_HELPER_DBG_STOP_STATUS_PHY_MASK = 0x0002, CHIP_HELPER_DBG_STOP_STATUS_BT_MASK = 0x0004, CHIP_HELPER_DBG_STOP_STATUS_SLEEP_STATUS_MAC_MASK = 0x0008, CHIP_HELPER_DBG_STOP_STATUS_SLEEP_STATUS_PHY_MASK = 0x0010, CHIP_HELPER_DBG_STOP_STATUS_SLEEP_STATUS_BT_MASK = 0x0020 }; /* Codes to disable the watchdog */ enum chip_helper_watchdog_disable_enum { CHIP_HELPER_WATCHDOG_DISABLE_CODE1 = 0x6734, CHIP_HELPER_WATCHDOG_DISABLE_CODE2 = 0xD6BF, CHIP_HELPER_WATCHDOG_DISABLE_CODE3 = 0xC31E }; /* Other bits have changed between versions */ enum chip_helper_gbl_misc_enum { CHIP_HELPER_GBL_MISC_SPI_STOP_OUT_EN_MASK = 0x0001, CHIP_HELPER_GBL_MISC_MMU_INIT_DONE_MASK = 0x0004 }; /* Coex status register, contains interrupt status and reset pullup status. * CHIP_HELPER_COEX_STATUS_RST_PULLS_MSB_MASK can be used to check * for WAPI on R03 chips and later. */ enum chip_helper_coex_status_mask_enum { CHIP_HELPER_COEX_STATUS_RST_PULLS_LSB_MASK = 0x0001, CHIP_HELPER_COEX_STATUS_RST_PULLS_MSB_MASK = 0x0008, CHIP_HELPER_COEX_STATUS_WL_FEC_PINS_LSB_MASK = 0x0010, CHIP_HELPER_COEX_STATUS_WL_FEC_PINS_MSB_MASK = 0x0080, CHIP_HELPER_COEX_STATUS_INT_UART_MASK = 0x0100, CHIP_HELPER_COEX_STATUS_INT_BT_LEG_MASK = 0x0200 }; /* How to select the different CPUs */ enum chip_helper_dbg_proc_sel_enum { CHIP_HELPER_DBG_PROC_SEL_MAC = 0, CHIP_HELPER_DBG_PROC_SEL_PHY = 1, CHIP_HELPER_DBG_PROC_SEL_BT = 2, CHIP_HELPER_DBG_PROC_SEL_NONE = 2, CHIP_HELPER_DBG_PROC_SEL_BOTH = 3 }; /* These are the only registers that we have to know the address of before we know the chip version. */ enum chip_helper_fixed_registers { /* This is the address of GBL_CHIP_VERISON on BC7, UF105x, UF60xx and anything later than that. */ CHIP_HELPER_UNIFI_GBL_CHIP_VERSION = 0xFE81, CHIP_HELPER_OLD_BLUECORE_GBL_CHIP_VERSION = 0xFF9A /* This isn't used at the moment (but might be needed to distinguish the BlueCore sub version?) */ /* CHIP_HELPER_OLD_BLUECORE_ANA_VERSION_ID = 0xFF7D */ }; /* Address-value pairs for defining initialisation values */ struct chip_helper_init_values { u16 addr; u16 value; }; /* A block of data that should be written to the device */ struct chip_helper_reset_values { u32 gp_address; u32 len; const u16 *data; }; /* * This is the C API. */ /* opaque type */ typedef const struct chip_device_desc_t ChipDescript; /* Return a NULL descriptor */ ChipDescript* ChipHelper_Null(void); /* This should get the correct version for any CSR chip. The two parameters are what is read from addresses 0xFF9A and 0xFE81 (OLD_BLUECORE_GBL_CHIP_VERSION and UNIFI_GBL_CHIP_VERSION). These should give a unique identity for most (all?) chips. FF9A is the old GBL_CHIP_VERSION register. If the high eight bits are zero then the chip is a new (BC7 +) one and FE81 is the _new_ GBL_CHIP_VERSION register. */ ChipDescript* ChipHelper_GetVersionAny(u16 from_FF9A, u16 from_FE81); /* The chip is a UniFi, but we don't know which type The parameter is the value of UNIFI_GBL_CHIP_VERSION (0xFE81) */ ChipDescript* ChipHelper_GetVersionUniFi(u16 version); /* This gets the version from the SDIO device id. This only gives quite a coarse grained version, so we should update once we hav access to the function N registers. */ ChipDescript* ChipHelper_GetVersionSdio(u8 sdio_version); /* The chip is some sort of BlueCore. If "age" is "pre_bc7" then "version" is what was read from FF9A. If "age" is bc7_or_later then "version" is read from FE81. If we don't know if we're pre or post BC7 then we should use "GetVersionAny". */ ChipDescript* ChipHelper_GetVersionBlueCore(enum chip_helper_bluecore_age age, u16 version); /* The main functions of this class are built with an X macro. This means we can generate the C and C++ versions from the same source without the two diverging. The DEF0 functions are simple and take no parameters. The first parameter to the macro is the return type. The second parameter is the function name and the third parameter is where to get the info from (this is hidden from the user). The DEF1 functions take one parameter. This time the third macro parameter is the type of this parameter, and the fourth macro parameter is the name of the parameter. The bodies of these functions are hand written. */ #define CHIP_HELPER_LIST(m) \ CHIP_HELPER_DEF0(m, (const char *, FriendlyName, friendly_name)) \ CHIP_HELPER_DEF0(m, (const char *, MarketingName, marketing_name)) \ CHIP_HELPER_DEF0(m, (u16, DBG_EMU_CMD, regs->dbg_emu_cmd)) \ CHIP_HELPER_DEF0(m, (u16, DBG_HOST_PROC_SELECT, regs->host.dbg_proc_select)) \ CHIP_HELPER_DEF0(m, (u16, DBG_HOST_STOP_STATUS, regs->host.dbg_stop_status)) \ CHIP_HELPER_DEF0(m, (u16, HOST_WINDOW1_PAGE, regs->host.window1_page)) \ CHIP_HELPER_DEF0(m, (u16, HOST_WINDOW2_PAGE, regs->host.window2_page)) \ CHIP_HELPER_DEF0(m, (u16, HOST_WINDOW3_PAGE, regs->host.window3_page)) \ CHIP_HELPER_DEF0(m, (u16, HOST_IO_LOG_ADDR, regs->host.io_log_addr)) \ CHIP_HELPER_DEF0(m, (u16, DBG_SPI_PROC_SELECT, regs->spi.dbg_proc_select)) \ CHIP_HELPER_DEF0(m, (u16, DBG_SPI_STOP_STATUS, regs->spi.dbg_stop_status)) \ CHIP_HELPER_DEF0(m, (u16, SPI_WINDOW1_PAGE, regs->spi.window1_page)) \ CHIP_HELPER_DEF0(m, (u16, SPI_WINDOW2_PAGE, regs->spi.window2_page)) \ CHIP_HELPER_DEF0(m, (u16, SPI_WINDOW3_PAGE, regs->spi.window3_page)) \ CHIP_HELPER_DEF0(m, (u16, SPI_IO_LOG_ADDR, regs->spi.io_log_addr)) \ CHIP_HELPER_DEF0(m, (u16, DBG_RESET, regs->dbg_reset)) \ CHIP_HELPER_DEF0(m, (u16, DBG_RESET_VALUE, regs->dbg_reset_value)) \ CHIP_HELPER_DEF0(m, (u16, DBG_RESET_WARN, regs->dbg_reset_warn)) \ CHIP_HELPER_DEF0(m, (u16, DBG_RESET_WARN_VALUE, regs->dbg_reset_warn_value)) \ CHIP_HELPER_DEF0(m, (u16, DBG_RESET_RESULT, regs->dbg_reset_result)) \ CHIP_HELPER_DEF0(m, (u16, WATCHDOG_DISABLE, regs->watchdog_disable)) \ CHIP_HELPER_DEF0(m, (u16, PROC_PC_SNOOP, regs->proc_pc_snoop)) \ CHIP_HELPER_DEF0(m, (u16, GBL_CHIP_VERSION, regs->gbl_chip_version)) \ CHIP_HELPER_DEF0(m, (u16, GBL_MISC_ENABLES, regs->gbl_misc_enables)) \ CHIP_HELPER_DEF0(m, (u16, XAP_PCH, regs->xap_pch)) \ CHIP_HELPER_DEF0(m, (u16, XAP_PCL, regs->xap_pcl)) \ CHIP_HELPER_DEF0(m, (u16, MAILBOX0, regs->mailbox0)) \ CHIP_HELPER_DEF0(m, (u16, MAILBOX1, regs->mailbox1)) \ CHIP_HELPER_DEF0(m, (u16, MAILBOX2, regs->mailbox2)) \ CHIP_HELPER_DEF0(m, (u16, MAILBOX3, regs->mailbox3)) \ CHIP_HELPER_DEF0(m, (u16, SDIO_HIP_HANDSHAKE, regs->sdio_hip_handshake)) \ CHIP_HELPER_DEF0(m, (u16, SDIO_HOST_INT, regs->sdio_host_int)) \ CHIP_HELPER_DEF0(m, (u16, COEX_STATUS, regs->coex_status)) \ CHIP_HELPER_DEF0(m, (u16, SHARED_IO_INTERRUPT, regs->shared_io_interrupt)) \ CHIP_HELPER_DEF0(m, (u32, PROGRAM_MEMORY_RAM_OFFSET, prog_offset.ram)) \ CHIP_HELPER_DEF0(m, (u32, PROGRAM_MEMORY_ROM_OFFSET, prog_offset.rom)) \ CHIP_HELPER_DEF0(m, (u32, PROGRAM_MEMORY_FLASH_OFFSET, prog_offset.flash)) \ CHIP_HELPER_DEF0(m, (u32, PROGRAM_MEMORY_EXT_SRAM_OFFSET, prog_offset.ext_sram)) \ CHIP_HELPER_DEF0(m, (u16, DATA_MEMORY_RAM_OFFSET, data_offset.ram)) \ CHIP_HELPER_DEF0(m, (s32, HasFlash, bools.has_flash)) \ CHIP_HELPER_DEF0(m, (s32, HasExtSram, bools.has_ext_sram)) \ CHIP_HELPER_DEF0(m, (s32, HasRom, bools.has_rom)) \ CHIP_HELPER_DEF0(m, (s32, HasBt, bools.has_bt)) \ CHIP_HELPER_DEF0(m, (s32, HasWLan, bools.has_wlan)) \ CHIP_HELPER_DEF1(m, (u16, WINDOW_ADDRESS, enum chip_helper_window_index, window)) \ CHIP_HELPER_DEF1(m, (u16, WINDOW_SIZE, enum chip_helper_window_index, window)) \ CHIP_HELPER_DEF1(m, (u16, MapAddress_SPI2HOST, u16, addr)) \ CHIP_HELPER_DEF1(m, (u16, MapAddress_HOST2SPI, u16, addr)) \ CHIP_HELPER_DEF1(m, (u32, ClockStartupSequence, const struct chip_helper_init_values **, val)) \ CHIP_HELPER_DEF1(m, (u32, HostResetSequence, const struct chip_helper_reset_values **, val)) /* Some magic to help the expansion */ #define CHIP_HELPER_DEF0(a, b) \ CHIP_HELPER_DEF0_ ## a b #define CHIP_HELPER_DEF1(a, b) \ CHIP_HELPER_DEF1_ ## a b /* Macros so that when we expand the list we get "C" function prototypes. */ #define CHIP_HELPER_DEF0_C_DEC(ret_type, name, info) \ ret_type ChipHelper_ ## name(ChipDescript * chip_help); #define CHIP_HELPER_DEF1_C_DEC(ret_type, name, type1, name1) \ ret_type ChipHelper_ ## name(ChipDescript * chip_help, type1 name1); CHIP_HELPER_LIST(C_DEC) /* FriendlyName MarketingName These two functions return human readable strings that describe the chip. FriendlyName returns something that a software engineer at CSR might understand. MarketingName returns something more like an external name for a CSR chip. */ /* DBG_EMU_CMD WATCHDOG_DISABLE PROC_PC_SNOOP GBL_CHIP_VERSION XAP_PCH XAP_PCL These registers are used to control the XAPs. */ /* DBG_HOST_PROC_SELECT DBG_HOST_STOP_STATUS HOST_WINDOW1_PAGE HOST_WINDOW2_PAGE HOST_WINDOW3_PAGE HOST_IO_LOG_ADDR DBG_SPI_PROC_SELECT DBG_SPI_STOP_STATUS SPI_WINDOW1_PAGE SPI_WINDOW2_PAGE SPI_WINDOW3_PAGE SPI_IO_LOG_ADDR These register are used to control the XAPs and the memory windows, normally while debugging the code on chip. There are two versons of these registers, one for access via SPI and another for access via the host interface. */ /* DBG_RESET DBG_RESET_VALUE DBG_RESET_WARN DBG_RESET_WARN_VALUE DBG_RESET_RESULT These registers are used to reset the XAP. This can be quite complex for some chips. If DBG_RESET_WARN is non zero the DBG_RESET_WARN_VALUE should be written to address DBG_RESET_WARN before the reset is perfeormed. DBG_RESET_VALUE should then be written to DBG_RESET to make the reset happen. The DBG_RESET_RESULT register should contain 0 if the reset was successful. */ /* GBL_MISC_ENABLES This register controls some special chip features. It should be used with care is it changes quite a lot between chip versions. */ /* MAILBOX0 MAILBOX1 MAILBOX2 MAILBOX3 The mailbox registers are for communication between the host and the firmware. There use is described in part by the host interface protcol specifcation. */ /* SDIO_HIP_HANDSHAKE This is one of the more important SDIO HIP registers. On some chips it has the same value as one of the mailbox registers and on other chips it is different. */ /* SDIO_HOST_INT SHARED_IO_INTERRUPT These registers are used by some versions of the host interface protocol specification. Their names should probably be changed to hide the registers and to expose the functions more. */ /* COEX_STATUS Coex status register, contains interrupt status and reset pullup status. The latter is used to detect WAPI. */ /* PROGRAM_MEMORY_RAM_OFFSET PROGRAM_MEMORY_ROM_OFFSET PROGRAM_MEMORY_FLASH_OFFSET PROGRAM_MEMORY_EXT_SRAM_OFFSET DATA_MEMORY_RAM_OFFSET These are constants that describe the offset of the different memory types in the two different address spaces. */ /* HasFlash HasExtSram HasRom HasBt HasWLan These are a set of bools describing the chip. */ /* WINDOW_ADDRESS WINDOW_SIZE These two functions return the size and address of the windows. The address is the address of the lowest value in the address map that is part of the window and the size is the number of visible words. Some of the windows have their lowest portion covered by registers. For these windows address is the first address after the registers and size is the siave excluding the part covered by registers. */ /* MapAddress_SPI2HOST MapAddress_HOST2SPI The debugging interface is duplicated on UniFi and later chips so that there are two versions - one over the SPI interaface and the other over the SDIO interface. These functions map the registers between these two interfaces. */ /* ClockStartupSequence This function returns the list of register value pairs that should be forced into UniFi to enable SPI communication. This set of registers is not needed if the firmware is running, but will be needed if the device is being booted from cold. These register writes enable the clocks and setup the PLL to a basic working state. SPI access might be unreliable until these writes have occurred (And they may take mulitple goes). */ /* HostResetSequence This returns a number of chunks of data and generic pointers. All of the XAPs should be stopped. The data should be written to the generic pointers. The instruction pointer for the MAC should then be set to the start of program memory and then the MAC should be "go"d. This will reset the chip in a reliable and orderly manner without resetting the SDIO interface. It is therefore not needed if the chip is being accessed by the SPI interface (the DBG_RESET_ mechanism can be used instead). */ /* The Decode Window function is more complex. For the window 'window' it tries to return the address and page register value needed to see offset 'offset' of memory type 'type'. It return 1 on success and 0 on failure. 'page' is what should be written to the page register. 'addr' is the address in the XAPs 16 address map to read from. 'len' is the length that we can read without having to change the page registers. */ s32 ChipHelper_DecodeWindow(ChipDescript *chip_help, enum chip_helper_window_index window, enum chip_helper_window_type type, u32 offset, u16 *page, u16 *addr, u32 *len); #endif