| 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 */
|
| +
|
|
|