From 5c105d9f3fd086aff195d3849dcf847d6b0bd927 Mon Sep 17 00:00:00 2001 From: blogic Date: Fri, 5 Oct 2012 10:12:53 +0000 Subject: branch Attitude Adjustment git-svn-id: svn://svn.openwrt.org/openwrt/branches/attitude_adjustment@33625 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- .../drivers/ar6000/miscdrv/common_drv.c | 467 +++++++++++++++++++++ 1 file changed, 467 insertions(+) create mode 100644 target/linux/s3c24xx/files-2.6.30/drivers/ar6000/miscdrv/common_drv.c (limited to 'target/linux/s3c24xx/files-2.6.30/drivers/ar6000/miscdrv/common_drv.c') diff --git a/target/linux/s3c24xx/files-2.6.30/drivers/ar6000/miscdrv/common_drv.c b/target/linux/s3c24xx/files-2.6.30/drivers/ar6000/miscdrv/common_drv.c new file mode 100644 index 000000000..4f1273466 --- /dev/null +++ b/target/linux/s3c24xx/files-2.6.30/drivers/ar6000/miscdrv/common_drv.c @@ -0,0 +1,467 @@ + +/* + * + * Copyright (c) 2004-2007 Atheros Communications Inc. + * All rights reserved. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + */ + +#include "a_config.h" +#include "athdefs.h" +#include "a_types.h" +#include "AR6Khwreg.h" +#include "targaddrs.h" +#include "a_osapi.h" +#include "hif.h" +#include "htc_api.h" +#include "bmi.h" +#include "bmi_msg.h" +#include "common_drv.h" +#include "a_debug.h" +#include "targaddrs.h" + +#define HOST_INTEREST_ITEM_ADDRESS(target, item) \ +(((TargetType) == TARGET_TYPE_AR6001) ? \ + AR6001_HOST_INTEREST_ITEM_ADDRESS(item) : \ + AR6002_HOST_INTEREST_ITEM_ADDRESS(item)) + + +/* Compile the 4BYTE version of the window register setup routine, + * This mitigates host interconnect issues with non-4byte aligned bus requests, some + * interconnects use bus adapters that impose strict limitations. + * Since diag window access is not intended for performance critical operations, the 4byte mode should + * be satisfactory even though it generates 4X the bus activity. */ + +#ifdef USE_4BYTE_REGISTER_ACCESS + + /* set the window address register (using 4-byte register access ). */ +A_STATUS ar6000_SetAddressWindowRegister(HIF_DEVICE *hifDevice, A_UINT32 RegisterAddr, A_UINT32 Address) +{ + A_STATUS status; + A_UINT8 addrValue[4]; + int i; + + /* write bytes 1,2,3 of the register to set the upper address bytes, the LSB is written + * last to initiate the access cycle */ + + for (i = 1; i <= 3; i++) { + /* fill the buffer with the address byte value we want to hit 4 times*/ + addrValue[0] = ((A_UINT8 *)&Address)[i]; + addrValue[1] = addrValue[0]; + addrValue[2] = addrValue[0]; + addrValue[3] = addrValue[0]; + + /* hit each byte of the register address with a 4-byte write operation to the same address, + * this is a harmless operation */ + status = HIFReadWrite(hifDevice, + RegisterAddr+i, + addrValue, + 4, + HIF_WR_SYNC_BYTE_FIX, + NULL); + if (status != A_OK) { + break; + } + } + + if (status != A_OK) { + AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write initial bytes of 0x%x to window reg: 0x%X \n", + RegisterAddr, Address)); + return status; + } + + /* write the address register again, this time write the whole 4-byte value. + * The effect here is that the LSB write causes the cycle to start, the extra + * 3 byte write to bytes 1,2,3 has no effect since we are writing the same values again */ + status = HIFReadWrite(hifDevice, + RegisterAddr, + (A_UCHAR *)(&Address), + 4, + HIF_WR_SYNC_BYTE_INC, + NULL); + + if (status != A_OK) { + AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to window reg: 0x%X \n", + RegisterAddr, Address)); + return status; + } + + return A_OK; + + + +} + + +#else + + /* set the window address register */ +A_STATUS ar6000_SetAddressWindowRegister(HIF_DEVICE *hifDevice, A_UINT32 RegisterAddr, A_UINT32 Address) +{ + A_STATUS status; + + /* write bytes 1,2,3 of the register to set the upper address bytes, the LSB is written + * last to initiate the access cycle */ + status = HIFReadWrite(hifDevice, + RegisterAddr+1, /* write upper 3 bytes */ + ((A_UCHAR *)(&Address))+1, + sizeof(A_UINT32)-1, + HIF_WR_SYNC_BYTE_INC, + NULL); + + if (status != A_OK) { + AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write initial bytes of 0x%x to window reg: 0x%X \n", + RegisterAddr, Address)); + return status; + } + + /* write the LSB of the register, this initiates the operation */ + status = HIFReadWrite(hifDevice, + RegisterAddr, + (A_UCHAR *)(&Address), + sizeof(A_UINT8), + HIF_WR_SYNC_BYTE_INC, + NULL); + + if (status != A_OK) { + AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to window reg: 0x%X \n", + RegisterAddr, Address)); + return status; + } + + return A_OK; +} + +#endif + +/* + * Read from the AR6000 through its diagnostic window. + * No cooperation from the Target is required for this. + */ +A_STATUS +ar6000_ReadRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data) +{ + A_STATUS status; + + /* set window register to start read cycle */ + status = ar6000_SetAddressWindowRegister(hifDevice, + WINDOW_READ_ADDR_ADDRESS, + *address); + + if (status != A_OK) { + return status; + } + + /* read the data */ + status = HIFReadWrite(hifDevice, + WINDOW_DATA_ADDRESS, + (A_UCHAR *)data, + sizeof(A_UINT32), + HIF_RD_SYNC_BYTE_INC, + NULL); + if (status != A_OK) { + AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot read from WINDOW_DATA_ADDRESS\n")); + return status; + } + + return status; +} + + +/* + * Write to the AR6000 through its diagnostic window. + * No cooperation from the Target is required for this. + */ +A_STATUS +ar6000_WriteRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data) +{ + A_STATUS status; + + /* set write data */ + status = HIFReadWrite(hifDevice, + WINDOW_DATA_ADDRESS, + (A_UCHAR *)data, + sizeof(A_UINT32), + HIF_WR_SYNC_BYTE_INC, + NULL); + if (status != A_OK) { + AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to WINDOW_DATA_ADDRESS\n", *data)); + return status; + } + + /* set window register, which starts the write cycle */ + return ar6000_SetAddressWindowRegister(hifDevice, + WINDOW_WRITE_ADDR_ADDRESS, + *address); +} + +A_STATUS +ar6000_ReadDataDiag(HIF_DEVICE *hifDevice, A_UINT32 address, + A_UCHAR *data, A_UINT32 length) +{ + A_UINT32 count; + A_STATUS status = A_OK; + + for (count = 0; count < length; count += 4, address += 4) { + if ((status = ar6000_ReadRegDiag(hifDevice, &address, + (A_UINT32 *)&data[count])) != A_OK) + { + break; + } + } + + return status; +} + +A_STATUS +ar6000_WriteDataDiag(HIF_DEVICE *hifDevice, A_UINT32 address, + A_UCHAR *data, A_UINT32 length) +{ + A_UINT32 count; + A_STATUS status = A_OK; + + for (count = 0; count < length; count += 4, address += 4) { + if ((status = ar6000_WriteRegDiag(hifDevice, &address, + (A_UINT32 *)&data[count])) != A_OK) + { + break; + } + } + + return status; +} + +A_STATUS +ar6000_reset_device_skipflash(HIF_DEVICE *hifDevice) +{ + int i; + struct forceROM_s { + A_UINT32 addr; + A_UINT32 data; + }; + struct forceROM_s *ForceROM; + int szForceROM; + A_UINT32 instruction; + + static struct forceROM_s ForceROM_REV2[] = { + /* NB: This works for old REV2 ROM (old). */ + {0x00001ff0, 0x175b0027}, /* jump instruction at 0xa0001ff0 */ + {0x00001ff4, 0x00000000}, /* nop instruction at 0xa0001ff4 */ + + {MC_REMAP_TARGET_ADDRESS, 0x00001ff0}, /* remap to 0xa0001ff0 */ + {MC_REMAP_COMPARE_ADDRESS, 0x01000040},/* ...from 0xbfc00040 */ + {MC_REMAP_SIZE_ADDRESS, 0x00000000}, /* ...1 cache line */ + {MC_REMAP_VALID_ADDRESS, 0x00000001}, /* ...remap is valid */ + + {LOCAL_COUNT_ADDRESS+0x10, 0}, /* clear BMI credit counter */ + + {RESET_CONTROL_ADDRESS, RESET_CONTROL_WARM_RST_MASK}, + }; + + static struct forceROM_s ForceROM_NEW[] = { + /* NB: This works for AR6000 ROM REV3 and beyond. */ + {LOCAL_SCRATCH_ADDRESS, AR6K_OPTION_IGNORE_FLASH}, + {LOCAL_COUNT_ADDRESS+0x10, 0}, /* clear BMI credit counter */ + {RESET_CONTROL_ADDRESS, RESET_CONTROL_WARM_RST_MASK}, + }; + + /* + * Examine a semi-arbitrary instruction that's different + * in REV2 and other revisions. + * NB: If a Host port does not require simultaneous support + * for multiple revisions of Target ROM, this code can be elided. + */ + (void)ar6000_ReadDataDiag(hifDevice, 0x01000040, + (A_UCHAR *)&instruction, 4); + + AR_DEBUG_PRINTF(ATH_LOG_ERR, ("instruction=0x%x\n", instruction)); + + if (instruction == 0x3c1aa200) { + /* It's an old ROM */ + ForceROM = ForceROM_REV2; + szForceROM = sizeof(ForceROM_REV2)/sizeof(*ForceROM); + AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Using OLD method\n")); + } else { + ForceROM = ForceROM_NEW; + szForceROM = sizeof(ForceROM_NEW)/sizeof(*ForceROM); + AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Using NEW method\n")); + } + + AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Force Target to execute from ROM....\n")); + for (i = 0; i < szForceROM; i++) + { + if (ar6000_WriteRegDiag(hifDevice, + &ForceROM[i].addr, + &ForceROM[i].data) != A_OK) + { + AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot force Target to execute ROM!\n")); + return A_ERROR; + } + } + + msleep(50); /* delay to allow dragon to come to BMI phase */ + return A_OK; +} + +/* reset device */ +A_STATUS ar6000_reset_device(HIF_DEVICE *hifDevice, A_UINT32 TargetType) +{ + +#if !defined(DWSIM) + A_STATUS status = A_OK; + A_UINT32 address; + A_UINT32 data; + + do { + + // address = RESET_CONTROL_ADDRESS; + data = RESET_CONTROL_COLD_RST_MASK; + + /* Hardcode the address of RESET_CONTROL_ADDRESS based on the target type */ + if (TargetType == TARGET_TYPE_AR6001) { + address = 0x0C000000; + } else { + if (TargetType == TARGET_TYPE_AR6002) { + address = 0x00004000; + } else { + A_ASSERT(0); + } + } + + status = ar6000_WriteRegDiag(hifDevice, &address, &data); + + if (A_FAILED(status)) { + break; + } + + /* + * Read back the RESET CAUSE register to ensure that the cold reset + * went through. + */ + msleep(2000); /* 2 second delay to allow things to settle down */ + + + // address = RESET_CAUSE_ADDRESS; + /* Hardcode the address of RESET_CAUSE_ADDRESS based on the target type */ + if (TargetType == TARGET_TYPE_AR6001) { + address = 0x0C0000CC; + } else { + if (TargetType == TARGET_TYPE_AR6002) { + address = 0x000040C0; + } else { + A_ASSERT(0); + } + } + + data = 0; + status = ar6000_ReadRegDiag(hifDevice, &address, &data); + + if (A_FAILED(status)) { + break; + } + + AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Reset Cause readback: 0x%X \n",data)); + data &= RESET_CAUSE_LAST_MASK; + if (data != 2) { + AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Unable to cold reset the target \n")); + } + + } while (FALSE); + + if (A_FAILED(status)) { + AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Failed to reset target \n")); + } +#endif + return A_OK; +} + +#define REG_DUMP_COUNT_AR6001 38 /* WORDs, derived from AR6001_regdump.h */ +#define REG_DUMP_COUNT_AR6002 32 /* WORDs, derived from AR6002_regdump.h */ + + +#if REG_DUMP_COUNT_AR6001 <= REG_DUMP_COUNT_AR6002 +#define REGISTER_DUMP_LEN_MAX REG_DUMP_COUNT_AR6002 +#else +#define REGISTER_DUMP_LEN_MAX REG_DUMP_COUNT_AR6001 +#endif + +void ar6000_dump_target_assert_info(HIF_DEVICE *hifDevice, A_UINT32 TargetType) +{ + A_UINT32 address; + A_UINT32 regDumpArea = 0; + A_STATUS status; + A_UINT32 regDumpValues[REGISTER_DUMP_LEN_MAX]; + A_UINT32 regDumpCount = 0; + A_UINT32 i; + + do { + + /* the reg dump pointer is copied to the host interest area */ + address = HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_failure_state); + + if (TargetType == TARGET_TYPE_AR6001) { + /* for AR6001, this is a fixed location because the ptr is actually stuck in cache, + * this may be fixed in later firmware versions */ + address = 0x18a0; + regDumpCount = REG_DUMP_COUNT_AR6001; + + } else if (TargetType == TARGET_TYPE_AR6002) { + + regDumpCount = REG_DUMP_COUNT_AR6002; + + } else { + A_ASSERT(0); + } + + /* read RAM location through diagnostic window */ + status = ar6000_ReadRegDiag(hifDevice, &address, ®DumpArea); + + if (A_FAILED(status)) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Failed to get ptr to register dump area \n")); + break; + } + + AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Location of register dump data: 0x%X \n",regDumpArea)); + + if (regDumpArea == 0) { + /* no reg dump */ + break; + } + + if (TargetType == TARGET_TYPE_AR6001) { + regDumpArea &= 0x0FFFFFFF; /* convert to physical address in target memory */ + } + + /* fetch register dump data */ + status = ar6000_ReadDataDiag(hifDevice, + regDumpArea, + (A_UCHAR *)®DumpValues[0], + regDumpCount * (sizeof(A_UINT32))); + + if (A_FAILED(status)) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Failed to get register dump \n")); + break; + } + + AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Register Dump: \n")); + + for (i = 0; i < regDumpCount; i++) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" %d : 0x%8.8X \n",i, regDumpValues[i])); + } + + } while (FALSE); + +} + -- cgit v1.2.3