794 lines
27 KiB
C
794 lines
27 KiB
C
/*****************************************************************************
|
|
|
|
(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.
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
#include "csr_wifi_hip_chiphelper_private.h"
|
|
|
|
#ifndef nelem
|
|
#define nelem(a) (sizeof(a) / sizeof(a[0]))
|
|
#endif
|
|
|
|
#define counted(foo) { nelem(foo), foo }
|
|
#define null_counted() { 0, NULL }
|
|
|
|
/* The init values are a set of register writes that we must
|
|
perform when we first connect to the chip to get it working.
|
|
They swicth on the correct clocks and possibly set the host
|
|
interface as a wkaeup source. They should not be used if
|
|
proper HIP opperation is required, but are useful before we
|
|
do a code download. */
|
|
static const struct chip_helper_init_values init_vals_v1[] = {
|
|
{ 0xFDBB, 0xFFFF },
|
|
{ 0xFDB6, 0x03FF },
|
|
{ 0xFDB1, 0x01E3 },
|
|
{ 0xFDB3, 0x0FFF },
|
|
{ 0xFEE3, 0x08F0 },
|
|
{ 0xFEE7, 0x3C3F },
|
|
{ 0xFEE6, 0x0050 },
|
|
{ 0xFDBA, 0x0000 }
|
|
};
|
|
|
|
static const struct chip_helper_init_values init_vals_v2[] = {
|
|
{ 0xFDB6, 0x0FFF },
|
|
{ 0xF023, 0x3F3F },
|
|
{ 0xFDB1, 0x01E3 },
|
|
{ 0xFDB3, 0x0FFF },
|
|
{ 0xF003, 0x08F0 },
|
|
{ 0xF007, 0x3C3F },
|
|
{ 0xF006, 0x0050 }
|
|
};
|
|
|
|
|
|
static const struct chip_helper_init_values init_vals_v22_v23[] = {
|
|
{ 0xF81C, 0x00FF },
|
|
/*{ 0x????, 0x???? }, */
|
|
{ 0xF80C, 0x1FFF },
|
|
{ 0xFA25, 0x001F },
|
|
{ 0xF804, 0x00FF },
|
|
{ 0xF802, 0x0FFF },
|
|
/*{ 0x????, 0x???? },
|
|
{ 0x????, 0x???? },
|
|
{ 0x????, 0x???? }*/
|
|
};
|
|
|
|
static const u16 reset_program_a_v1_or_v2[] = {
|
|
0x0000
|
|
};
|
|
static const u16 reset_program_b_v1_or_v2[] = {
|
|
0x0010, 0xFE00, 0xA021, 0xFF00, 0x8111, 0x0009, 0x0CA4, 0x0114,
|
|
0x0280, 0x04F8, 0xFE00, 0x6F25, 0x06E0, 0x0010, 0xFC00, 0x0121,
|
|
0xFC00, 0x0225, 0xFE00, 0x7125, 0xFE00, 0x6D11, 0x03F0, 0xFE00,
|
|
0x6E25, 0x0008, 0x00E0
|
|
};
|
|
|
|
static const struct chip_helper_reset_values reset_program_v1_or_v2[] =
|
|
{
|
|
{
|
|
MAKE_GP(REGISTERS, 0x000C),
|
|
nelem(reset_program_a_v1_or_v2),
|
|
reset_program_a_v1_or_v2
|
|
},
|
|
{
|
|
MAKE_GP(MAC_PMEM, 0x000000),
|
|
nelem(reset_program_b_v1_or_v2),
|
|
reset_program_b_v1_or_v2
|
|
}
|
|
};
|
|
|
|
static const struct chip_map_address_t unifi_map_address_v1_v2[] =
|
|
{
|
|
{ 0xFE9F, 0xFE7B }, /* PM1_BANK_SELECT */
|
|
{ 0xFE9E, 0xFE78 }, /* PM2_BANK_SELECT */
|
|
{ 0xFE9D, 0xFE7E }, /* SHARED_DMEM_PAGE */
|
|
{ 0xFE91, 0xFE90 }, /* PROC_SELECT */
|
|
{ 0xFE8D, 0xFE8C }, /* STOP_STATUS */
|
|
};
|
|
|
|
static const struct chip_map_address_t unifi_map_address_v22_v23[] =
|
|
{
|
|
{ 0xF8F9, 0xF8AC }, /* GW1_CONFIG */
|
|
{ 0xF8FA, 0xF8AD }, /* GW2_CONFIG */
|
|
{ 0xF8FB, 0xF8AE }, /* GW3_CONFIG */
|
|
{ 0xF830, 0xF81E }, /* PROC_SELECT */
|
|
{ 0xF831, 0xF81F }, /* STOP_STATUS */
|
|
{ 0xF8FC, 0xF8AF }, /* IO_LOG_ADDRESS */
|
|
};
|
|
|
|
static const struct chip_device_regs_t unifi_device_regs_null =
|
|
{
|
|
0xFE81, /* GBL_CHIP_VERSION */
|
|
0x0000, /* GBL_MISC_ENABLES */
|
|
0x0000, /* DBG_EMU_CMD */
|
|
{
|
|
0x0000, /* HOST.DBG_PROC_SELECT */
|
|
0x0000, /* HOST.DBG_STOP_STATUS */
|
|
0x0000, /* HOST.WINDOW1_PAGE */
|
|
0x0000, /* HOST.WINDOW2_PAGE */
|
|
0x0000, /* HOST.WINDOW3_PAGE */
|
|
0x0000 /* HOST.IO_LOG_ADDR */
|
|
},
|
|
{
|
|
0x0000, /* SPI.DBG_PROC_SELECT */
|
|
0x0000, /* SPI.DBG_STOP_STATUS */
|
|
0x0000, /* SPI.WINDOW1_PAGE */
|
|
0x0000, /* SPI.WINDOW2_PAGE */
|
|
0x0000, /* SPI.WINDOW3_PAGE */
|
|
0x0000 /* SPI.IO_LOG_ADDR */
|
|
},
|
|
0x0000, /* DBG_RESET */
|
|
0x0000, /* > DBG_RESET_VALUE */
|
|
0x0000, /* DBG_RESET_WARN */
|
|
0x0000, /* DBG_RESET_WARN_VALUE */
|
|
0x0000, /* DBG_RESET_RESULT */
|
|
0xFFE9, /* XAP_PCH */
|
|
0xFFEA, /* XAP_PCL */
|
|
0x0000, /* PROC_PC_SNOOP */
|
|
0x0000, /* WATCHDOG_DISABLE */
|
|
0x0000, /* MAILBOX0 */
|
|
0x0000, /* MAILBOX1 */
|
|
0x0000, /* MAILBOX2 */
|
|
0x0000, /* MAILBOX3 */
|
|
0x0000, /* SDIO_HOST_INT */
|
|
0x0000, /* SHARED_IO_INTERRUPT */
|
|
0x0000, /* SDIO HIP HANDSHAKE */
|
|
0x0000 /* COEX_STATUS */
|
|
};
|
|
|
|
/* UF105x */
|
|
static const struct chip_device_regs_t unifi_device_regs_v1 =
|
|
{
|
|
0xFE81, /* GBL_CHIP_VERSION */
|
|
0xFE87, /* GBL_MISC_ENABLES */
|
|
0xFE9C, /* DBG_EMU_CMD */
|
|
{
|
|
0xFE90, /* HOST.DBG_PROC_SELECT */
|
|
0xFE8C, /* HOST.DBG_STOP_STATUS */
|
|
0xFE7B, /* HOST.WINDOW1_PAGE */
|
|
0xFE78, /* HOST.WINDOW2_PAGE */
|
|
0xFE7E, /* HOST.WINDOW3_PAGE */
|
|
0x0000 /* HOST.IO_LOG_ADDR */
|
|
},
|
|
{
|
|
0xFE91, /* SPI.DBG_PROC_SELECT */
|
|
0xFE8D, /* SPI.DBG_STOP_STATUS */
|
|
0xFE9F, /* SPI.WINDOW1_PAGE */
|
|
0xFE9E, /* SPI.WINDOW2_PAGE */
|
|
0xFE9D, /* SPI.WINDOW3_PAGE */
|
|
0x0000 /* SPI.IO_LOG_ADDR */
|
|
},
|
|
0xFE92, /* DBG_RESET */
|
|
0x0001, /* > DBG_RESET_VALUE */
|
|
0xFDA0, /* DBG_RESET_WARN (HOST_SELECT) */
|
|
0x0000, /* DBG_RESET_WARN_VALUE */
|
|
0xFE92, /* DBG_RESET_RESULT */
|
|
0xFFE9, /* XAP_PCH */
|
|
0xFFEA, /* XAP_PCL */
|
|
0x0051, /* PROC_PC_SNOOP */
|
|
0xFE70, /* WATCHDOG_DISABLE */
|
|
0xFE6B, /* MAILBOX0 */
|
|
0xFE6A, /* MAILBOX1 */
|
|
0xFE69, /* MAILBOX2 */
|
|
0xFE68, /* MAILBOX3 */
|
|
0xFE67, /* SDIO_HOST_INT */
|
|
0xFE65, /* SHARED_IO_INTERRUPT */
|
|
0xFDE9, /* SDIO HIP HANDSHAKE */
|
|
0x0000 /* COEX_STATUS */
|
|
};
|
|
|
|
/* UF2... */
|
|
static const struct chip_device_regs_t unifi_device_regs_v2 =
|
|
{
|
|
0xFE81, /* GBL_CHIP_VERSION */
|
|
0xFE87, /* GBL_MISC_ENABLES */
|
|
0xFE9C, /* DBG_EMU_CMD */
|
|
{
|
|
0xFE90, /* HOST.DBG_PROC_SELECT */
|
|
0xFE8C, /* HOST.DBG_STOP_STATUS */
|
|
0xFE7B, /* HOST.WINDOW1_PAGE */
|
|
0xFE78, /* HOST.WINDOW2_PAGE */
|
|
0xFE7E, /* HOST.WINDOW3_PAGE */
|
|
0x0000 /* HOST.IO_LOG_ADDR */
|
|
},
|
|
{
|
|
0xFE91, /* SPI.DBG_PROC_SELECT */
|
|
0xFE8D, /* SPI.DBG_STOP_STATUS */
|
|
0xFE9F, /* SPI.WINDOW1_PAGE */
|
|
0xFE9E, /* SPI.WINDOW2_PAGE */
|
|
0xFE9D, /* SPI.WINDOW3_PAGE */
|
|
0x0000 /* SPI.IO_LOG_ADDR */
|
|
},
|
|
0xFE92, /* DBG_RESET */
|
|
0x0000, /* > DBG_RESET_VALUE */
|
|
0xFDE9, /* DBG_RESET_WARN (TEST_FLASH_DATA - SHARED_MAILBOX2B) */
|
|
0xFFFF, /* DBG_RESET_WARN_VALUE */
|
|
0xFDE9, /* DBG_RESET_RESULT (TEST_FLASH_DATA) */
|
|
0xFFE9, /* XAP_PCH */
|
|
0xFFEA, /* XAP_PCL */
|
|
0x0051, /* PROC_PC_SNOOP */
|
|
0xFE70, /* WATCHDOG_DISABLE */
|
|
0xFE6B, /* MAILBOX0 */
|
|
0xFE6A, /* MAILBOX1 */
|
|
0xFE69, /* MAILBOX2 */
|
|
0xFE68, /* MAILBOX3 */
|
|
0xFE67, /* SDIO_HOST_INT */
|
|
0xFE65, /* SHARED_IO_INTERRUPT */
|
|
0xFE69, /* SDIO HIP HANDSHAKE */
|
|
0x0000 /* COEX_STATUS */
|
|
};
|
|
|
|
/* UF60xx */
|
|
static const struct chip_device_regs_t unifi_device_regs_v22_v23 =
|
|
{
|
|
0xFE81, /* GBL_CHIP_VERSION */
|
|
0xF84F, /* GBL_MISC_ENABLES */
|
|
0xF81D, /* DBG_EMU_CMD */
|
|
{
|
|
0xF81E, /* HOST.DBG_PROC_SELECT */
|
|
0xF81F, /* HOST.DBG_STOP_STATUS */
|
|
0xF8AC, /* HOST.WINDOW1_PAGE */
|
|
0xF8AD, /* HOST.WINDOW2_PAGE */
|
|
0xF8AE, /* HOST.WINDOW3_PAGE */
|
|
0xF8AF /* HOST.IO_LOG_ADDR */
|
|
},
|
|
{
|
|
0xF830, /* SPI.DBG_PROC_SELECT */
|
|
0xF831, /* SPI.DBG_STOP_STATUS */
|
|
0xF8F9, /* SPI.WINDOW1_PAGE */
|
|
0xF8FA, /* SPI.WINDOW2_PAGE */
|
|
0xF8FB, /* SPI.WINDOW3_PAGE */
|
|
0xF8FC /* SPI.IO_LOG_ADDR */
|
|
},
|
|
0xF82F, /* DBG_RESET */
|
|
0x0001, /* > DBG_RESET_VALUE */
|
|
0x0000, /* DBG_RESET_WARN */
|
|
0x0000, /* DBG_RESET_WARN_VALUE */
|
|
0xF82F, /* DBG_RESET_RESULT */
|
|
0xFFE9, /* XAP_PCH */
|
|
0xFFEA, /* XAP_PCL */
|
|
0x001B, /* PROC_PC_SNOOP */
|
|
0x0055, /* WATCHDOG_DISABLE */
|
|
0xF84B, /* MAILBOX0 */
|
|
0xF84C, /* MAILBOX1 */
|
|
0xF84D, /* MAILBOX2 */
|
|
0xF84E, /* MAILBOX3 */
|
|
0xF92F, /* SDIO_HOST_INT */
|
|
0xF92B, /* SDIO_FROMHOST_SCRTACH0 / SHARED_IO_INTERRUPT */
|
|
0xF84D, /* SDIO HIP HANDSHAKE (MAILBOX2) */
|
|
0xF9FB /* COEX_STATUS */
|
|
};
|
|
|
|
/* Program memory window on UF105x. */
|
|
static const struct window_shift_info_t prog_window_array_unifi_v1_v2[CHIP_HELPER_WT_COUNT] =
|
|
{
|
|
{ TRUE, 11, 0x0200 }, /* CODE RAM */
|
|
{ TRUE, 11, 0x0000 }, /* FLASH */
|
|
{ TRUE, 11, 0x0400 }, /* External SRAM */
|
|
{ FALSE, 0, 0 }, /* ROM */
|
|
{ FALSE, 0, 0 } /* SHARED */
|
|
};
|
|
|
|
/* Shared memory window on UF105x. */
|
|
static const struct window_shift_info_t shared_window_array_unifi_v1_v2[CHIP_HELPER_WT_COUNT] =
|
|
{
|
|
{ FALSE, 0, 0 }, /* CODE RAM */
|
|
{ FALSE, 0, 0 }, /* FLASH */
|
|
{ FALSE, 0, 0 }, /* External SRAM */
|
|
{ FALSE, 0, 0 }, /* ROM */
|
|
{ TRUE, 11, 0x0000 } /* SHARED */
|
|
};
|
|
|
|
/* One of the Generic Windows on UF60xx and later. */
|
|
static const struct window_shift_info_t generic_window_array_unifi_v22_v23[CHIP_HELPER_WT_COUNT] =
|
|
{
|
|
{ TRUE, 11, 0x3800 }, /* CODE RAM */
|
|
{ FALSE, 0, 0 }, /* FLASH */
|
|
{ FALSE, 0, 0 }, /* External SRAM */
|
|
{ TRUE, 11, 0x2000 }, /* ROM */
|
|
{ TRUE, 11, 0x0000 } /* SHARED */
|
|
};
|
|
|
|
/* The three windows on UF105x. */
|
|
static const struct window_info_t prog1_window_unifi_v1_v2 = { 0x0000, 0x2000, 0x0080, prog_window_array_unifi_v1_v2 };
|
|
static const struct window_info_t prog2_window_unifi_v1_v2 = { 0x2000, 0x2000, 0x0000, prog_window_array_unifi_v1_v2 };
|
|
static const struct window_info_t shared_window_unifi_v1_v2 = { 0x4000, 0x2000, 0x0000, shared_window_array_unifi_v1_v2 };
|
|
|
|
/* The three windows on UF60xx and later. */
|
|
static const struct window_info_t generic1_window_unifi_v22_v23 = { 0x0000, 0x2000, 0x0080, generic_window_array_unifi_v22_v23 };
|
|
static const struct window_info_t generic2_window_unifi_v22_v23 = { 0x2000, 0x2000, 0x0000, generic_window_array_unifi_v22_v23 };
|
|
static const struct window_info_t generic3_window_unifi_v22_v23 = { 0x4000, 0x2000, 0x0000, generic_window_array_unifi_v22_v23 };
|
|
|
|
static const struct chip_device_desc_t chip_device_desc_null =
|
|
{
|
|
{ FALSE, 0x0000, 0x0000, 0x00 },
|
|
"",
|
|
"",
|
|
null_counted(), /* init */
|
|
null_counted(), /* reset_prog */
|
|
&unifi_device_regs_null, /* regs */
|
|
{
|
|
FALSE, /* has_flash */
|
|
FALSE, /* has_ext_sram */
|
|
FALSE, /* has_rom */
|
|
FALSE, /* has_bt */
|
|
FALSE, /* has_wlan */
|
|
},
|
|
null_counted(),
|
|
/* prog_offset */
|
|
{
|
|
0x00000000,
|
|
0x00000000,
|
|
0x00000000,
|
|
0x00000000
|
|
},
|
|
/* data_offset */
|
|
{
|
|
0x0000 /* ram */
|
|
},
|
|
/* windows */
|
|
{
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
}
|
|
};
|
|
|
|
static const struct chip_device_desc_t unifi_device_desc_v1 =
|
|
{
|
|
{ FALSE, 0xf0ff, 0x1001, 0x01 }, /* UF105x R01 */
|
|
"UF105x",
|
|
"UniFi-1",
|
|
counted(init_vals_v1), /* init */
|
|
counted(reset_program_v1_or_v2), /* reset_prog */
|
|
&unifi_device_regs_v1, /* regs */
|
|
{
|
|
TRUE, /* has_flash */
|
|
TRUE, /* has_ext_sram */
|
|
FALSE, /* has_rom */
|
|
FALSE, /* has_bt */
|
|
TRUE, /* has_wlan */
|
|
},
|
|
counted(unifi_map_address_v1_v2), /* map */
|
|
/* prog_offset */
|
|
{
|
|
0x00100000, /* ram */
|
|
0x00000000, /* rom (invalid) */
|
|
0x00000000, /* flash */
|
|
0x00200000, /* ext_ram */
|
|
},
|
|
/* data_offset */
|
|
{
|
|
0x8000 /* ram */
|
|
},
|
|
/* windows */
|
|
{
|
|
&prog1_window_unifi_v1_v2,
|
|
&prog2_window_unifi_v1_v2,
|
|
&shared_window_unifi_v1_v2
|
|
}
|
|
};
|
|
|
|
static const struct chip_device_desc_t unifi_device_desc_v2 =
|
|
{
|
|
{ FALSE, 0xf0ff, 0x2001, 0x02 }, /* UF2... R02 */
|
|
"UF2...",
|
|
"UniFi-2",
|
|
counted(init_vals_v2), /* init */
|
|
counted(reset_program_v1_or_v2), /* reset_prog */
|
|
&unifi_device_regs_v2, /* regs */
|
|
{
|
|
TRUE, /* has_flash */
|
|
TRUE, /* has_ext_sram */
|
|
FALSE, /* has_rom */
|
|
FALSE, /* has_bt */
|
|
TRUE, /* has_wlan */
|
|
},
|
|
counted(unifi_map_address_v1_v2), /* map */
|
|
/* prog_offset */
|
|
{
|
|
0x00100000, /* ram */
|
|
0x00000000, /* rom (invalid) */
|
|
0x00000000, /* flash */
|
|
0x00200000, /* ext_ram */
|
|
},
|
|
/* data_offset */
|
|
{
|
|
0x8000 /* ram */
|
|
},
|
|
/* windows */
|
|
{
|
|
&prog1_window_unifi_v1_v2,
|
|
&prog2_window_unifi_v1_v2,
|
|
&shared_window_unifi_v1_v2
|
|
}
|
|
};
|
|
|
|
static const struct chip_device_desc_t unifi_device_desc_v3 =
|
|
{
|
|
{ FALSE, 0xf0ff, 0x3001, 0x02 }, /* UF2... R03 */
|
|
"UF2...",
|
|
"UniFi-3",
|
|
counted(init_vals_v2), /* init */
|
|
counted(reset_program_v1_or_v2), /* reset_prog */
|
|
&unifi_device_regs_v2, /* regs */
|
|
{
|
|
TRUE, /* has_flash */
|
|
TRUE, /* has_ext_sram */
|
|
FALSE, /* has_rom */
|
|
FALSE, /* has_bt */
|
|
TRUE, /* has_wlan */
|
|
},
|
|
counted(unifi_map_address_v1_v2), /* map */
|
|
/* prog_offset */
|
|
{
|
|
0x00100000, /* ram */
|
|
0x00000000, /* rom (invalid) */
|
|
0x00000000, /* flash */
|
|
0x00200000, /* ext_ram */
|
|
},
|
|
/* data_offset */
|
|
{
|
|
0x8000 /* ram */
|
|
},
|
|
/* windows */
|
|
{
|
|
&prog1_window_unifi_v1_v2,
|
|
&prog2_window_unifi_v1_v2,
|
|
&shared_window_unifi_v1_v2
|
|
}
|
|
};
|
|
|
|
static const struct chip_device_desc_t unifi_device_desc_v22 =
|
|
{
|
|
{ FALSE, 0x00ff, 0x0022, 0x07 }, /* UF60xx */
|
|
"UF60xx",
|
|
"UniFi-4",
|
|
counted(init_vals_v22_v23), /* init */
|
|
null_counted(), /* reset_prog */
|
|
&unifi_device_regs_v22_v23, /* regs */
|
|
{
|
|
FALSE, /* has_flash */
|
|
FALSE, /* has_ext_sram */
|
|
TRUE, /* has_rom */
|
|
FALSE, /* has_bt */
|
|
TRUE, /* has_wlan */
|
|
},
|
|
counted(unifi_map_address_v22_v23), /* map */
|
|
/* prog_offset */
|
|
{
|
|
0x00C00000, /* ram */
|
|
0x00000000, /* rom */
|
|
0x00000000, /* flash (invalid) */
|
|
0x00000000, /* ext_ram (invalid) */
|
|
},
|
|
/* data_offset */
|
|
{
|
|
0x8000 /* ram */
|
|
},
|
|
/* windows */
|
|
{
|
|
&generic1_window_unifi_v22_v23,
|
|
&generic2_window_unifi_v22_v23,
|
|
&generic3_window_unifi_v22_v23
|
|
}
|
|
};
|
|
|
|
static const struct chip_device_desc_t unifi_device_desc_v23 =
|
|
{
|
|
{ FALSE, 0x00ff, 0x0023, 0x08 }, /* UF.... */
|
|
"UF....",
|
|
"UF.... (5)",
|
|
counted(init_vals_v22_v23), /* init */
|
|
null_counted(), /* reset_prog */
|
|
&unifi_device_regs_v22_v23, /* regs */
|
|
{
|
|
FALSE, /* has_flash */
|
|
FALSE, /* has_ext_sram */
|
|
TRUE, /* has_rom */
|
|
TRUE, /* has_bt */
|
|
TRUE, /* has_wlan */
|
|
},
|
|
counted(unifi_map_address_v22_v23),
|
|
/* prog_offset */
|
|
{
|
|
0x00C00000, /* ram */
|
|
0x00000000, /* rom */
|
|
0x00000000, /* flash (invalid) */
|
|
0x00000000, /* ext_sram (invalid) */
|
|
},
|
|
/* data_offset */
|
|
{
|
|
0x8000 /* ram */
|
|
},
|
|
/* windows */
|
|
{
|
|
&generic1_window_unifi_v22_v23,
|
|
&generic2_window_unifi_v22_v23,
|
|
&generic3_window_unifi_v22_v23
|
|
}
|
|
};
|
|
|
|
static const struct chip_device_desc_t hyd_wlan_subsys_desc_v1 =
|
|
{
|
|
{ FALSE, 0x00ff, 0x0044, 0x00 }, /* UF.... */
|
|
"HYD...",
|
|
"HYD... ",
|
|
counted(init_vals_v22_v23), /* init */
|
|
null_counted(), /* reset_prog */
|
|
&unifi_device_regs_v22_v23, /* regs */
|
|
{
|
|
FALSE, /* has_flash */
|
|
FALSE, /* has_ext_sram */
|
|
TRUE, /* has_rom */
|
|
FALSE, /* has_bt */
|
|
TRUE, /* has_wlan */
|
|
},
|
|
counted(unifi_map_address_v22_v23),
|
|
/* prog_offset */
|
|
{
|
|
0x00C00000, /* ram */
|
|
0x00000000, /* rom */
|
|
0x00000000, /* flash (invalid) */
|
|
0x00000000, /* ext_sram (invalid) */
|
|
},
|
|
/* data_offset */
|
|
{
|
|
0x8000 /* ram */
|
|
},
|
|
/* windows */
|
|
{
|
|
&generic1_window_unifi_v22_v23,
|
|
&generic2_window_unifi_v22_v23,
|
|
&generic3_window_unifi_v22_v23
|
|
}
|
|
};
|
|
|
|
|
|
/* This is the list of all chips that we know about. I'm
|
|
assuming that the order here will be important - we
|
|
might have multiple entries witrh the same SDIO id for
|
|
instance. The first one in this list will be the one
|
|
that is returned if a search is done on only that id.
|
|
The client will then have to call GetVersionXXX again
|
|
but with more detailed info.
|
|
|
|
I don't know if we need to signal this up to the client
|
|
in some way?
|
|
|
|
(We get the SDIO id before we know anything else about
|
|
the chip. We might not be able to read any of the other
|
|
registers at first, but we still need to know about the
|
|
chip). */
|
|
static const struct chip_device_desc_t *chip_ver_to_desc[] =
|
|
{
|
|
&unifi_device_desc_v1, /* UF105x R01 */
|
|
&unifi_device_desc_v2, /* UF2... R02 */
|
|
&unifi_device_desc_v3, /* UF2... R03 */
|
|
&unifi_device_desc_v22, /* UF60xx */
|
|
&unifi_device_desc_v23, /* UF.... */
|
|
&hyd_wlan_subsys_desc_v1
|
|
};
|
|
|
|
ChipDescript* ChipHelper_GetVersionSdio(u8 sdio_ver)
|
|
{
|
|
u32 i;
|
|
|
|
for (i = 0; i < nelem(chip_ver_to_desc); i++)
|
|
{
|
|
if (chip_ver_to_desc[i]->chip_version.sdio == sdio_ver)
|
|
{
|
|
return chip_ver_to_desc[i];
|
|
}
|
|
}
|
|
|
|
return &chip_device_desc_null;
|
|
}
|
|
|
|
|
|
ChipDescript* ChipHelper_GetVersionAny(u16 from_FF9A, u16 from_FE81)
|
|
{
|
|
u32 i;
|
|
|
|
if ((from_FF9A & 0xFF00) != 0)
|
|
{
|
|
for (i = 0; i < nelem(chip_ver_to_desc); i++)
|
|
{
|
|
if (chip_ver_to_desc[i]->chip_version.pre_bc7 &&
|
|
((from_FF9A & chip_ver_to_desc[i]->chip_version.mask) ==
|
|
chip_ver_to_desc[i]->chip_version.result))
|
|
{
|
|
return chip_ver_to_desc[i];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < nelem(chip_ver_to_desc); i++)
|
|
{
|
|
if (!chip_ver_to_desc[i]->chip_version.pre_bc7 &&
|
|
((from_FE81 & chip_ver_to_desc[i]->chip_version.mask) ==
|
|
chip_ver_to_desc[i]->chip_version.result))
|
|
{
|
|
return chip_ver_to_desc[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
return &chip_device_desc_null;
|
|
}
|
|
|
|
|
|
ChipDescript* ChipHelper_GetVersionUniFi(u16 ver)
|
|
{
|
|
return ChipHelper_GetVersionAny(0x0000, ver);
|
|
}
|
|
|
|
|
|
ChipDescript *ChipHelper_Null(void)
|
|
{
|
|
return &chip_device_desc_null;
|
|
}
|
|
|
|
|
|
ChipDescript* ChipHelper_GetVersionBlueCore(enum chip_helper_bluecore_age bc_age, u16 version)
|
|
{
|
|
if (bc_age == chip_helper_bluecore_pre_bc7)
|
|
{
|
|
return ChipHelper_GetVersionAny(version, 0x0000);
|
|
}
|
|
else
|
|
{
|
|
return ChipHelper_GetVersionAny(0x0000, version);
|
|
}
|
|
}
|
|
|
|
|
|
/* Expand the DEF0 functions into simple code to return the
|
|
correct thing. The DEF1 functions expand to nothing in
|
|
this X macro expansion. */
|
|
#define CHIP_HELPER_DEF0_C_DEF(ret_type, name, info) \
|
|
ret_type ChipHelper_ ## name(ChipDescript * chip_help) \
|
|
{ \
|
|
return chip_help->info; \
|
|
}
|
|
#define CHIP_HELPER_DEF1_C_DEF(ret_type, name, type1, name1)
|
|
|
|
CHIP_HELPER_LIST(C_DEF)
|
|
|
|
/*
|
|
* Map register addresses between HOST and SPI access.
|
|
*/
|
|
u16 ChipHelper_MapAddress_SPI2HOST(ChipDescript *chip_help, u16 addr)
|
|
{
|
|
u32 i;
|
|
for (i = 0; i < chip_help->map.len; i++)
|
|
{
|
|
if (chip_help->map.vals[i].spi == addr)
|
|
{
|
|
return chip_help->map.vals[i].host;
|
|
}
|
|
}
|
|
return addr;
|
|
}
|
|
|
|
|
|
u16 ChipHelper_MapAddress_HOST2SPI(ChipDescript *chip_help, u16 addr)
|
|
{
|
|
u32 i;
|
|
for (i = 0; i < chip_help->map.len; i++)
|
|
{
|
|
if (chip_help->map.vals[i].host == addr)
|
|
{
|
|
return chip_help->map.vals[i].spi;
|
|
}
|
|
}
|
|
return addr;
|
|
}
|
|
|
|
|
|
/* The address returned by this function is the start of the
|
|
window in the address space, that is where we can start
|
|
accessing data from. If a section of the window at the
|
|
start is unusable because something else is cluttering up
|
|
the address map then that is taken into account and this
|
|
function returns that address justt past that. */
|
|
u16 ChipHelper_WINDOW_ADDRESS(ChipDescript *chip_help,
|
|
enum chip_helper_window_index window)
|
|
{
|
|
if (window < CHIP_HELPER_WINDOW_COUNT &&
|
|
chip_help->windows[window] != NULL)
|
|
{
|
|
return chip_help->windows[window]->address + chip_help->windows[window]->blocked;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* This returns the size of the window minus any blocked section */
|
|
u16 ChipHelper_WINDOW_SIZE(ChipDescript *chip_help,
|
|
enum chip_helper_window_index window)
|
|
{
|
|
if (window < CHIP_HELPER_WINDOW_COUNT &&
|
|
chip_help->windows[window] != NULL)
|
|
{
|
|
return chip_help->windows[window]->size - chip_help->windows[window]->blocked;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Get the register writes we should do to make sure that
|
|
the chip is running with most clocks on. */
|
|
u32 ChipHelper_ClockStartupSequence(ChipDescript *chip_help,
|
|
const struct chip_helper_init_values **val)
|
|
{
|
|
*val = chip_help->init.vals;
|
|
return chip_help->init.len;
|
|
}
|
|
|
|
|
|
/* Get the set of values tat we should write to the chip to perform a reset. */
|
|
u32 ChipHelper_HostResetSequence(ChipDescript *chip_help,
|
|
const struct chip_helper_reset_values **val)
|
|
{
|
|
*val = chip_help->reset_prog.vals;
|
|
return chip_help->reset_prog.len;
|
|
}
|
|
|
|
|
|
/* Decode a windowed access to the chip. */
|
|
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)
|
|
{
|
|
const struct window_info_t *win;
|
|
const struct window_shift_info_t *mode;
|
|
u16 of, pg;
|
|
|
|
if (window >= CHIP_HELPER_WINDOW_COUNT)
|
|
{
|
|
return FALSE;
|
|
}
|
|
if ((win = chip_help->windows[window]) == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (type >= CHIP_HELPER_WT_COUNT)
|
|
{
|
|
return FALSE;
|
|
}
|
|
if ((mode = &win->mode[type]) == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (!mode->allowed)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pg = (u16)(offset >> mode->page_shift) + mode->page_offset;
|
|
of = (u16)(offset & ((1 << mode->page_shift) - 1));
|
|
/* If 'blocked' is zero this does nothing, else decrease
|
|
the page register and increase the offset until we aren't
|
|
in the blocked region of the window. */
|
|
while (of < win->blocked)
|
|
{
|
|
of += 1 << mode->page_shift;
|
|
pg--;
|
|
}
|
|
*page = pg;
|
|
*addr = win->address + of;
|
|
*len = win->size - of;
|
|
return TRUE;
|
|
}
|
|
|
|
|