diff options
| -rw-r--r-- | target/linux/ar71xx/patches-3.3/620-MIPS-ath79-OTP-support.patch | 166 | 
1 files changed, 166 insertions, 0 deletions
| 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 index 000000000..096329291 --- /dev/null +++ b/target/linux/ar71xx/patches-3.3/620-MIPS-ath79-OTP-support.patch @@ -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 +  */ | 
