Index: chromeos/drivers/ath6kl/os/linux/eeprom.c |
diff --git a/chromeos/drivers/ath6kl/os/linux/eeprom.c b/chromeos/drivers/ath6kl/os/linux/eeprom.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..7bdd0ac8e0ddddf851b9a9ea9793e0895d8c940f |
--- /dev/null |
+++ b/chromeos/drivers/ath6kl/os/linux/eeprom.c |
@@ -0,0 +1,585 @@ |
+/* |
+ * |
+ * Copyright (c) 2004-2009 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 "ar6000_drv.h" |
+#include "htc.h" |
+#include <linux/fs.h> |
+ |
+#include "AR6002/hw2.0/hw/apb_map.h" |
+#include "AR6002/hw2.0/hw/gpio_reg.h" |
+#ifndef ANDROID_ENV |
+#include "AR6002/hw2.0/hw/rtc_reg.h" |
+#endif |
+#include "AR6002/hw2.0/hw/si_reg.h" |
+ |
+// |
+// defines |
+// |
+ |
+#define MAX_FILENAME 1023 |
+#define EEPROM_WAIT_LIMIT 16 |
+ |
+#define HOST_INTEREST_ITEM_ADDRESS(item) \ |
+ (AR6002_HOST_INTEREST_ITEM_ADDRESS(item)) |
+ |
+#define EEPROM_SZ 768 |
+ |
+/* soft mac */ |
+#define ATH_MAC_LEN 6 |
+#define ATH_SOFT_MAC_TMP_BUF_LEN 64 |
+unsigned char mac_addr[ATH_MAC_LEN]; |
+unsigned char soft_mac_tmp_buf[ATH_SOFT_MAC_TMP_BUF_LEN]; |
+char *p_mac = NULL; |
+/* soft mac */ |
+ |
+// |
+// static variables |
+// |
+ |
+static A_UCHAR eeprom_data[EEPROM_SZ]; |
+static A_UINT32 sys_sleep_reg; |
+static HIF_DEVICE *p_bmi_device; |
+ |
+// |
+// Functions |
+// |
+ |
+/* soft mac */ |
+static int |
+wmic_ether_aton(const char *orig, A_UINT8 *eth) |
+{ |
+ const char *bufp; |
+ int i; |
+ |
+ i = 0; |
+ for(bufp = orig; *bufp != '\0'; ++bufp) { |
+ unsigned int val; |
+ unsigned char c = *bufp++; |
+ if (c >= '0' && c <= '9') val = c - '0'; |
+ else if (c >= 'a' && c <= 'f') val = c - 'a' + 10; |
+ else if (c >= 'A' && c <= 'F') val = c - 'A' + 10; |
+ else { |
+ printk("%s: MAC value is invalid\n", __FUNCTION__); |
+ break; |
+ } |
+ |
+ val <<= 4; |
+ c = *bufp++; |
+ if (c >= '0' && c <= '9') val |= c - '0'; |
+ else if (c >= 'a' && c <= 'f') val |= c - 'a' + 10; |
+ else if (c >= 'A' && c <= 'F') val |= c - 'A' + 10; |
+ else { |
+ printk("%s: MAC value is invalid\n", __FUNCTION__); |
+ break; |
+ } |
+ |
+ eth[i] = (unsigned char) (val & 0377); |
+ if(++i == ATH_MAC_LEN) { |
+ /* That's it. Any trailing junk? */ |
+ if (*bufp != '\0') { |
+ return 0; |
+ } |
+ return 1; |
+ } |
+ if (*bufp != ':') |
+ break; |
+ } |
+ return 0; |
+} |
+ |
+static void |
+update_mac(unsigned char* eeprom, int size, unsigned char* macaddr) |
+{ |
+ int i; |
+ A_UINT16* ptr = (A_UINT16*)(eeprom+4); |
+ A_UINT16 checksum = 0; |
+ |
+ memcpy(eeprom+10,macaddr,6); |
+ |
+ *ptr = 0; |
+ ptr = (A_UINT16*)eeprom; |
+ |
+ for (i=0; i<size; i+=2) { |
+ checksum ^= *ptr++; |
+ } |
+ checksum = ~checksum; |
+ |
+ ptr = (A_UINT16*)(eeprom+4); |
+ *ptr = checksum; |
+ return; |
+} |
+/* soft mac */ |
+ |
+/* Read a Target register and return its value. */ |
+inline void |
+BMI_read_reg(A_UINT32 address, A_UINT32 *pvalue) |
+{ |
+ BMIReadSOCRegister(p_bmi_device, address, pvalue); |
+} |
+ |
+/* Write a value to a Target register. */ |
+inline void |
+BMI_write_reg(A_UINT32 address, A_UINT32 value) |
+{ |
+ BMIWriteSOCRegister(p_bmi_device, address, value); |
+} |
+ |
+/* Read Target memory word and return its value. */ |
+inline void |
+BMI_read_mem(A_UINT32 address, A_UINT32 *pvalue) |
+{ |
+ BMIReadMemory(p_bmi_device, address, (A_UCHAR*)(pvalue), 4); |
+} |
+ |
+/* Write a word to a Target memory. */ |
+inline void |
+BMI_write_mem(A_UINT32 address, A_UINT8 *p_data, A_UINT32 sz) |
+{ |
+ BMIWriteMemory(p_bmi_device, address, (A_UCHAR*)(p_data), sz); |
+} |
+ |
+/* |
+ * Enable and configure the Target's Serial Interface |
+ * so we can access the EEPROM. |
+ */ |
+static void |
+enable_SI(HIF_DEVICE *p_device) |
+{ |
+ A_UINT32 regval; |
+ |
+ printk("%s\n", __FUNCTION__); |
+ |
+ p_bmi_device = p_device; |
+ |
+ BMI_read_reg(RTC_BASE_ADDRESS+SYSTEM_SLEEP_OFFSET, &sys_sleep_reg); |
+ BMI_write_reg(RTC_BASE_ADDRESS+SYSTEM_SLEEP_OFFSET, SYSTEM_SLEEP_DISABLE_SET(1)); //disable system sleep temporarily |
+ |
+ BMI_read_reg(RTC_BASE_ADDRESS+CLOCK_CONTROL_OFFSET, ®val); |
+ regval &= ~CLOCK_CONTROL_SI0_CLK_MASK; |
+ BMI_write_reg(RTC_BASE_ADDRESS+CLOCK_CONTROL_OFFSET, regval); |
+ |
+ BMI_read_reg(RTC_BASE_ADDRESS+RESET_CONTROL_OFFSET, ®val); |
+ regval &= ~RESET_CONTROL_SI0_RST_MASK; |
+ BMI_write_reg(RTC_BASE_ADDRESS+RESET_CONTROL_OFFSET, regval); |
+ |
+ |
+ BMI_read_reg(GPIO_BASE_ADDRESS+GPIO_PIN0_OFFSET, ®val); |
+ regval &= ~GPIO_PIN0_CONFIG_MASK; |
+ BMI_write_reg(GPIO_BASE_ADDRESS+GPIO_PIN0_OFFSET, regval); |
+ |
+ BMI_read_reg(GPIO_BASE_ADDRESS+GPIO_PIN1_OFFSET, ®val); |
+ regval &= ~GPIO_PIN1_CONFIG_MASK; |
+ BMI_write_reg(GPIO_BASE_ADDRESS+GPIO_PIN1_OFFSET, regval); |
+ |
+ /* SI_CONFIG = 0x500a6; */ |
+ regval = SI_CONFIG_BIDIR_OD_DATA_SET(1) | |
+ SI_CONFIG_I2C_SET(1) | |
+ SI_CONFIG_POS_SAMPLE_SET(1) | |
+ SI_CONFIG_INACTIVE_CLK_SET(1) | |
+ SI_CONFIG_INACTIVE_DATA_SET(1) | |
+ SI_CONFIG_DIVIDER_SET(6); |
+ BMI_write_reg(SI_BASE_ADDRESS+SI_CONFIG_OFFSET, regval); |
+ |
+} |
+ |
+static void |
+disable_SI(void) |
+{ |
+ A_UINT32 regval; |
+ |
+ printk("%s\n", __FUNCTION__); |
+ |
+ BMI_write_reg(RTC_BASE_ADDRESS+RESET_CONTROL_OFFSET, RESET_CONTROL_SI0_RST_MASK); |
+ BMI_read_reg(RTC_BASE_ADDRESS+CLOCK_CONTROL_OFFSET, ®val); |
+ regval |= CLOCK_CONTROL_SI0_CLK_MASK; |
+ BMI_write_reg(RTC_BASE_ADDRESS+CLOCK_CONTROL_OFFSET, regval);//Gate SI0 clock |
+ BMI_write_reg(RTC_BASE_ADDRESS+SYSTEM_SLEEP_OFFSET, sys_sleep_reg); //restore system sleep setting |
+} |
+ |
+/* |
+ * Tell the Target to start an 8-byte read from EEPROM, |
+ * putting the results in Target RX_DATA registers. |
+ */ |
+static void |
+request_8byte_read(int offset) |
+{ |
+ A_UINT32 regval; |
+ |
+// printk("%s: request_8byte_read from offset 0x%x\n", __FUNCTION__, offset); |
+ |
+ |
+ /* SI_TX_DATA0 = read from offset */ |
+ regval =(0xa1<<16)| |
+ ((offset & 0xff)<<8) | |
+ (0xa0 | ((offset & 0xff00)>>7)); |
+ |
+ BMI_write_reg(SI_BASE_ADDRESS+SI_TX_DATA0_OFFSET, regval); |
+ |
+ regval = SI_CS_START_SET(1) | |
+ SI_CS_RX_CNT_SET(8) | |
+ SI_CS_TX_CNT_SET(3); |
+ BMI_write_reg(SI_BASE_ADDRESS+SI_CS_OFFSET, regval); |
+} |
+ |
+/* |
+ * Tell the Target to start a 4-byte write to EEPROM, |
+ * writing values from Target TX_DATA registers. |
+ */ |
+static void |
+request_4byte_write(int offset, A_UINT32 data) |
+{ |
+ A_UINT32 regval; |
+ |
+ printk("%s: request_4byte_write (0x%x) to offset 0x%x\n", __FUNCTION__, data, offset); |
+ |
+ /* SI_TX_DATA0 = write data to offset */ |
+ regval = ((data & 0xffff) <<16) | |
+ ((offset & 0xff)<<8) | |
+ (0xa0 | ((offset & 0xff00)>>7)); |
+ BMI_write_reg(SI_BASE_ADDRESS+SI_TX_DATA0_OFFSET, regval); |
+ |
+ regval = data >> 16; |
+ BMI_write_reg(SI_BASE_ADDRESS+SI_TX_DATA1_OFFSET, regval); |
+ |
+ regval = SI_CS_START_SET(1) | |
+ SI_CS_RX_CNT_SET(0) | |
+ SI_CS_TX_CNT_SET(6); |
+ BMI_write_reg(SI_BASE_ADDRESS+SI_CS_OFFSET, regval); |
+} |
+ |
+/* |
+ * Check whether or not an EEPROM request that was started |
+ * earlier has completed yet. |
+ */ |
+static A_BOOL |
+request_in_progress(void) |
+{ |
+ A_UINT32 regval; |
+ |
+ /* Wait for DONE_INT in SI_CS */ |
+ BMI_read_reg(SI_BASE_ADDRESS+SI_CS_OFFSET, ®val); |
+ |
+// printk("%s: request in progress SI_CS=0x%x\n", __FUNCTION__, regval); |
+ if (regval & SI_CS_DONE_ERR_MASK) { |
+ printk("%s: EEPROM signaled ERROR (0x%x)\n", __FUNCTION__, regval); |
+ } |
+ |
+ return (!(regval & SI_CS_DONE_INT_MASK)); |
+} |
+ |
+/* |
+ * try to detect the type of EEPROM,16bit address or 8bit address |
+ */ |
+ |
+static void eeprom_type_detect(void) |
+{ |
+ A_UINT32 regval; |
+ A_UINT8 i = 0; |
+ |
+ request_8byte_read(0x100); |
+ /* Wait for DONE_INT in SI_CS */ |
+ do{ |
+ BMI_read_reg(SI_BASE_ADDRESS+SI_CS_OFFSET, ®val); |
+ if (regval & SI_CS_DONE_ERR_MASK) { |
+ printk("%s: ERROR : address type was wrongly set\n", __FUNCTION__); |
+ break; |
+ } |
+ if (i++ == EEPROM_WAIT_LIMIT) { |
+ printk("%s: EEPROM not responding\n", __FUNCTION__); |
+ } |
+ } while(!(regval & SI_CS_DONE_INT_MASK)); |
+} |
+ |
+/* |
+ * Extract the results of a completed EEPROM Read request |
+ * and return them to the caller. |
+ */ |
+inline void |
+read_8byte_results(A_UINT32 *data) |
+{ |
+ /* Read SI_RX_DATA0 and SI_RX_DATA1 */ |
+ BMI_read_reg(SI_BASE_ADDRESS+SI_RX_DATA0_OFFSET, &data[0]); |
+ BMI_read_reg(SI_BASE_ADDRESS+SI_RX_DATA1_OFFSET, &data[1]); |
+} |
+ |
+ |
+/* |
+ * Wait for a previously started command to complete. |
+ * Timeout if the command is takes "too long". |
+ */ |
+static void |
+wait_for_eeprom_completion(void) |
+{ |
+ int i=0; |
+ |
+ while (request_in_progress()) { |
+ if (i++ == EEPROM_WAIT_LIMIT) { |
+ printk("%s: EEPROM not responding\n", __FUNCTION__); |
+ } |
+ } |
+} |
+ |
+/* |
+ * High-level function which starts an 8-byte read, |
+ * waits for it to complete, and returns the result. |
+ */ |
+static void |
+fetch_8bytes(int offset, A_UINT32 *data) |
+{ |
+ request_8byte_read(offset); |
+ wait_for_eeprom_completion(); |
+ read_8byte_results(data); |
+ |
+ /* Clear any pending intr */ |
+ BMI_write_reg(SI_BASE_ADDRESS+SI_CS_OFFSET, SI_CS_DONE_INT_MASK); |
+} |
+ |
+/* |
+ * High-level function which starts a 4-byte write, |
+ * and waits for it to complete. |
+ */ |
+inline void |
+commit_4bytes(int offset, A_UINT32 data) |
+{ |
+ request_4byte_write(offset, data); |
+ wait_for_eeprom_completion(); |
+} |
+/* ATHENV */ |
+#ifdef ANDROID_ENV |
+void eeprom_ar6000_transfer(HIF_DEVICE *device, char *fake_file, char *p_mac) |
+{ |
+ A_UINT32 first_word; |
+ A_UINT32 board_data_addr; |
+ int i; |
+ |
+ printk("%s: Enter\n", __FUNCTION__); |
+ |
+ enable_SI(device); |
+ eeprom_type_detect(); |
+ |
+ if (fake_file) { |
+ /* |
+ * Transfer from file to Target RAM. |
+ * Fetch source data from file. |
+ */ |
+ mm_segment_t oldfs; |
+ struct file *filp; |
+ struct inode *inode = NULL; |
+ int length; |
+ |
+ /* open file */ |
+ oldfs = get_fs(); |
+ set_fs(KERNEL_DS); |
+ filp = filp_open(fake_file, O_RDONLY, S_IRUSR); |
+ |
+ if (IS_ERR(filp)) { |
+ printk("%s: file %s filp_open error\n", __FUNCTION__, fake_file); |
+ set_fs(oldfs); |
+ return; |
+ } |
+ |
+ if (!filp->f_op) { |
+ printk("%s: File Operation Method Error\n", __FUNCTION__); |
+ filp_close(filp, NULL); |
+ set_fs(oldfs); |
+ return; |
+ } |
+ |
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) |
+ inode = filp->f_path.dentry->d_inode; |
+#else |
+ inode = filp->f_dentry->d_inode; |
+#endif |
+ |
+ if (!inode) { |
+ printk("%s: Get inode from filp failed\n", __FUNCTION__); |
+ filp_close(filp, NULL); |
+ set_fs(oldfs); |
+ return; |
+ } |
+ |
+ printk("%s file offset opsition: %xh\n", __FUNCTION__, (unsigned)filp->f_pos); |
+ |
+ /* file's size */ |
+ length = i_size_read(inode->i_mapping->host); |
+ printk("%s: length=%d\n", __FUNCTION__, length); |
+ if (length != EEPROM_SZ) { |
+ printk("%s: The file's size is not as expected\n", __FUNCTION__); |
+ filp_close(filp, NULL); |
+ set_fs(oldfs); |
+ return; |
+ } |
+ |
+ /* read data */ |
+ if (filp->f_op->read(filp, eeprom_data, length, &filp->f_pos) != length) { |
+ printk("%s: file read error\n", __FUNCTION__); |
+ filp_close(filp, NULL); |
+ set_fs(oldfs); |
+ return; |
+ } |
+ |
+ /* read data out successfully */ |
+ filp_close(filp, NULL); |
+ set_fs(oldfs); |
+ } else { |
+ /* |
+ * Read from EEPROM to file OR transfer from EEPROM to Target RAM. |
+ * Fetch EEPROM_SZ Bytes of Board Data, 8 bytes at a time. |
+ */ |
+ |
+ fetch_8bytes(0, (A_UINT32 *)(&eeprom_data[0])); |
+ |
+ /* Check the first word of EEPROM for validity */ |
+ first_word = *((A_UINT32 *)eeprom_data); |
+ |
+ if ((first_word == 0) || (first_word == 0xffffffff)) { |
+ printk("Did not find EEPROM with valid Board Data.\n"); |
+ } |
+ |
+ for (i=8; i<EEPROM_SZ; i+=8) { |
+ fetch_8bytes(i, (A_UINT32 *)(&eeprom_data[i])); |
+ } |
+ } |
+ |
+ /* soft mac */ |
+ if (p_mac) { |
+ |
+ mm_segment_t oldfs; |
+ struct file *filp; |
+ struct inode *inode = NULL; |
+ int length; |
+ |
+ /* open file */ |
+ oldfs = get_fs(); |
+ set_fs(KERNEL_DS); |
+ filp = filp_open(p_mac, O_RDONLY, S_IRUSR); |
+ |
+ printk("%s try to open file %s\n", __FUNCTION__, p_mac); |
+ |
+ if (IS_ERR(filp)) { |
+ printk("%s: file %s filp_open error\n", __FUNCTION__, p_mac); |
+ set_fs(oldfs); |
+ return; |
+ } |
+ |
+ if (!filp->f_op) { |
+ printk("%s: File Operation Method Error\n", __FUNCTION__); |
+ filp_close(filp, NULL); |
+ set_fs(oldfs); |
+ return; |
+ } |
+ |
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) |
+ inode = filp->f_path.dentry->d_inode; |
+#else |
+ inode = filp->f_dentry->d_inode; |
+#endif |
+ if (!inode) { |
+ printk("%s: Get inode from filp failed\n", __FUNCTION__); |
+ filp_close(filp, NULL); |
+ set_fs(oldfs); |
+ return; |
+ } |
+ |
+ printk("%s file offset opsition: %xh\n", __FUNCTION__, (unsigned)filp->f_pos); |
+ |
+ /* file's size */ |
+ length = i_size_read(inode->i_mapping->host); |
+ printk("%s: length=%d\n", __FUNCTION__, length); |
+ if (length > ATH_SOFT_MAC_TMP_BUF_LEN) { |
+ printk("%s: MAC file's size is not as expected\n", __FUNCTION__); |
+ filp_close(filp, NULL); |
+ set_fs(oldfs); |
+ return; |
+ } |
+ |
+ /* read data */ |
+ if (filp->f_op->read(filp, soft_mac_tmp_buf, length, &filp->f_pos) != length) { |
+ printk("%s: file read error\n", __FUNCTION__); |
+ filp_close(filp, NULL); |
+ set_fs(oldfs); |
+ return; |
+ } |
+ |
+#if 0 |
+ /* the data we just read */ |
+ printk("%s: mac address from the file:\n", __FUNCTION__); |
+ for (i = 0; i < length; i++) |
+ printk("[%c(0x%x)],", soft_mac_tmp_buf[i], soft_mac_tmp_buf[i]); |
+ printk("\n"); |
+#endif |
+ |
+ /* read data out successfully */ |
+ filp_close(filp, NULL); |
+ set_fs(oldfs); |
+ |
+ /* convert mac address */ |
+ if (!wmic_ether_aton(soft_mac_tmp_buf, mac_addr)) { |
+ printk("%s: convert mac value fail\n", __FUNCTION__); |
+ return; |
+ } |
+ |
+#if 0 |
+ /* the converted mac address */ |
+ printk("%s: the converted mac value\n", __FUNCTION__); |
+ for (i = 0; i < ATH_MAC_LEN; i++) |
+ printk("[0x%x],", mac_addr[i]); |
+ printk("\n"); |
+#endif |
+ } |
+ /* soft mac */ |
+ |
+ /* Determine where in Target RAM to write Board Data */ |
+ BMI_read_mem( HOST_INTEREST_ITEM_ADDRESS(hi_board_data), &board_data_addr); |
+ if (board_data_addr == 0) { |
+ printk("hi_board_data is zero\n"); |
+ } |
+ |
+ /* soft mac */ |
+#if 1 |
+ /* Update MAC address in RAM */ |
+ if (p_mac) { |
+ update_mac(eeprom_data, EEPROM_SZ, mac_addr); |
+ } |
+#endif |
+#if 0 |
+ /* mac address in eeprom array */ |
+ printk("%s: mac values in eeprom array\n", __FUNCTION__); |
+ for (i = 10; i < 10 + 6; i++) |
+ printk("[0x%x],", eeprom_data[i]); |
+ printk("\n"); |
+#endif |
+ /* soft mac */ |
+ |
+ /* Write EEPROM data to Target RAM */ |
+ BMI_write_mem(board_data_addr, ((A_UINT8 *)eeprom_data), EEPROM_SZ); |
+ |
+ /* Record the fact that Board Data IS initialized */ |
+ { |
+ A_UINT32 one = 1; |
+ BMI_write_mem(HOST_INTEREST_ITEM_ADDRESS(hi_board_data_initialized), |
+ (A_UINT8 *)&one, sizeof(A_UINT32)); |
+ } |
+ |
+ disable_SI(); |
+} |
+#endif |
+/* ATHENV */ |
+ |