123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- --- a/arch/mips/ath79/dev-wmac.c
- +++ b/arch/mips/ath79/dev-wmac.c
- @@ -167,6 +167,137 @@ static void qca955x_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
- @@ -14,5 +14,6 @@
-
- void ath79_register_wmac(u8 *cal_data, u8 *mac_addr);
- void ath79_register_wmac_simple(void);
- +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
- @@ -112,6 +112,14 @@
- #define QCA955X_EHCI1_BASE 0x1b400000
- #define QCA955X_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
- */
|