ar71xx: add support for reading the MAC address from OTP ROM on AR933x
authorFelix Fietkau <nbd@openwrt.org>
Tue, 19 Jun 2012 00:21:58 +0000 (00:21 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Tue, 19 Jun 2012 00:21:58 +0000 (00:21 +0000)
SVN-Revision: 32446

target/linux/ar71xx/patches-3.3/620-MIPS-ath79-OTP-support.patch [new file with mode: 0644]

diff --git a/target/linux/ar71xx/patches-3.3/620-MIPS-ath79-OTP-support.patch b/target/linux/ar71xx/patches-3.3/620-MIPS-ath79-OTP-support.patch
new file mode 100644 (file)
index 0000000..0963292
--- /dev/null
@@ -0,0 +1,166 @@
+--- a/arch/mips/ath79/dev-wmac.c
++++ b/arch/mips/ath79/dev-wmac.c
+@@ -121,6 +121,137 @@ static void ar934x_wmac_setup(void)
+               ath79_wmac_data.is_clk_25mhz = true;
+ }
++static bool __init
++ar93xx_wmac_otp_read_word(void __iomem *base, int addr, u32 *data)
++{
++      int timeout = 1000;
++      u32 val;
++
++      __raw_readl(base + AR9300_OTP_BASE + (4 * addr));
++      while (timeout--) {
++              val = __raw_readl(base + AR9300_OTP_STATUS);
++              if ((val & AR9300_OTP_STATUS_TYPE) == AR9300_OTP_STATUS_VALID)
++                      break;
++
++              udelay(10);
++      }
++
++      if (!timeout)
++              return false;
++
++      *data = __raw_readl(base + AR9300_OTP_READ_DATA);
++      return true;
++}
++
++static bool __init
++ar93xx_wmac_otp_read(void __iomem *base, int addr, u8 *dest, int len)
++{
++      u32 data;
++      int i;
++
++      for (i = 0; i < len; i++) {
++              int offset = 8 * ((addr - i) % 4);
++
++              if (!ar93xx_wmac_otp_read_word(base, (addr - i) / 4, &data))
++                      return false;
++
++              dest[i] = (data >> offset) & 0xff;
++      }
++
++      return true;
++}
++
++static bool __init
++ar93xx_wmac_otp_uncompress(void __iomem *base, int addr, int len, u8 *dest,
++                         int dest_start, int dest_len)
++{
++      int dest_bytes = 0;
++      int offset = 0;
++      int end = addr - len;
++      u8 hdr[2];
++
++      while (addr > end) {
++              if (!ar93xx_wmac_otp_read(base, addr, hdr, 2))
++                      return false;
++
++              addr -= 2;
++              offset += hdr[0];
++
++              if (offset <= dest_start + dest_len &&
++                  offset + len >= dest_start) {
++                      int data_offset = 0;
++                      int dest_offset = 0;
++                      int copy_len;
++
++                      if (offset < dest_start)
++                              data_offset = dest_start - offset;
++                      else
++                              dest_offset = offset - dest_start;
++
++                      copy_len = len - data_offset;
++                      if (copy_len > dest_len - dest_offset)
++                              copy_len = dest_len - dest_offset;
++
++                      ar93xx_wmac_otp_read(base, addr - data_offset,
++                                           dest + dest_offset,
++                                           copy_len);
++
++                      dest_bytes += copy_len;
++              }
++              addr -= hdr[1];
++      }
++      return !!dest_bytes;
++}
++
++bool __init ar93xx_wmac_read_mac_address(u8 *dest)
++{
++      void __iomem *base;
++      bool ret = false;
++      int addr = 0x1ff;
++      unsigned int len;
++      u32 hdr_u32;
++      u8 *hdr = (u8 *) &hdr_u32;
++      u8 mac[6] = { 0x00, 0x02, 0x03, 0x04, 0x05, 0x06 };
++      int mac_start = 2, mac_end = 8;
++
++      BUG_ON(!soc_is_ar933x() && !soc_is_ar934x());
++      base = ioremap_nocache(AR933X_WMAC_BASE, AR933X_WMAC_SIZE);
++      while (addr > sizeof(hdr)) {
++              if (!ar93xx_wmac_otp_read(base, addr, hdr, sizeof(hdr)))
++                      break;
++
++              if (hdr_u32 == 0 || hdr_u32 == ~0)
++                      break;
++
++              len = (hdr[1] << 4) | (hdr[2] >> 4);
++              addr -= 4;
++
++              switch (hdr[0] >> 5) {
++              case 0:
++                      if (len < mac_end)
++                              break;
++
++                      ar93xx_wmac_otp_read(base, addr - mac_start, mac, 6);
++                      ret = true;
++                      break;
++              case 3:
++                      ret |= ar93xx_wmac_otp_uncompress(base, addr, len, mac,
++                                                        mac_start, 6);
++                      break;
++              default:
++                      break;
++              }
++
++              addr -= len + 2;
++      }
++
++      iounmap(base);
++      if (ret)
++              memcpy(dest, mac, 6);
++
++      return ret;
++}
++
+ void __init ath79_register_wmac(u8 *cal_data, u8 *mac_addr)
+ {
+       if (soc_is_ar913x())
+--- a/arch/mips/ath79/dev-wmac.h
++++ b/arch/mips/ath79/dev-wmac.h
+@@ -13,5 +13,6 @@
+ #define _ATH79_DEV_WMAC_H
+ void ath79_register_wmac(u8 *cal_data, u8 *mac_addr);
++bool ar93xx_wmac_read_mac_address(u8 *dest);
+ #endif /* _ATH79_DEV_WMAC_H */
+--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
++++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+@@ -78,6 +78,14 @@
+ #define AR934X_EHCI_BASE      0x1b000000
+ #define AR934X_EHCI_SIZE      0x1000
++#define AR9300_OTP_BASE               0x14000
++#define AR9300_OTP_STATUS     0x15f18
++#define AR9300_OTP_STATUS_TYPE                0x7
++#define AR9300_OTP_STATUS_VALID               0x4
++#define AR9300_OTP_STATUS_ACCESS_BUSY 0x2
++#define AR9300_OTP_STATUS_SM_BUSY     0x1
++#define AR9300_OTP_READ_DATA  0x15f1c
++
+ /*
+  * DDR_CTRL block
+  */