diff options
Diffstat (limited to 'target/linux/ath79/image/lzma-loader/src')
-rw-r--r-- | target/linux/ath79/image/lzma-loader/src/ar71xx_regs.h | 17 | ||||
-rw-r--r-- | target/linux/ath79/image/lzma-loader/src/board.c | 133 |
2 files changed, 150 insertions, 0 deletions
diff --git a/target/linux/ath79/image/lzma-loader/src/ar71xx_regs.h b/target/linux/ath79/image/lzma-loader/src/ar71xx_regs.h index 19a4785bb4..245042fdab 100644 --- a/target/linux/ath79/image/lzma-loader/src/ar71xx_regs.h +++ b/target/linux/ath79/image/lzma-loader/src/ar71xx_regs.h @@ -128,6 +128,17 @@ #define AR9300_OTP_STATUS_SM_BUSY 0x1 #define AR9300_OTP_READ_DATA 0x15f1c +#define QCA955X_OTP_BASE (AR71XX_APB_BASE + 0x00130000) +#define QCA955X_OTP_REG_MEM_0 0x0000 +#define QCA955X_OTP_REG_INTF2 0x1008 +#define QCA955X_OTP_REG_STATUS0 0x1018 +#define QCA955X_OTP_STATUS0_EFUSE_VALID BIT(2) + +#define QCA955X_OTP_REG_STATUS1 0x101c +#define QCA955X_OTP_REG_LDO_CTRL 0x1024 +#define QCA955X_OTP_REG_LDO_STATUS 0x102c +#define QCA955X_OTP_LDO_STATUS_POWER_ON BIT(0) + /* * DDR_CTRL block */ @@ -344,6 +355,7 @@ #define QCA955X_RESET_REG_BOOTSTRAP 0xb0 #define QCA955X_RESET_REG_EXT_INT_STATUS 0xac +#define QCA955X_RESET_REG_RESET_MODULE 0x1c #define MISC_INT_ETHSW BIT(12) #define MISC_INT_TIMER4 BIT(10) @@ -436,6 +448,9 @@ #define AR934X_RESET_MBOX BIT(1) #define AR934X_RESET_I2S BIT(0) +#define QCA955X_RESET_SGMII_ANALOG BIT(12) +#define QCA955X_RESET_SGMII BIT(8) + #define AR933X_BOOTSTRAP_MDIO_GPIO_EN BIT(18) #define AR933X_BOOTSTRAP_EEPBUSY BIT(4) #define AR933X_BOOTSTRAP_REF_CLK_40 BIT(0) @@ -722,4 +737,6 @@ #define QCA955X_ETH_CFG_RGMII_GMAC0 BIT(0) #define QCA955X_ETH_CFG_SGMII_GMAC0 BIT(6) +#define QCA955X_GMAC_REG_SGMII_SERDES 0x0018 + #endif /* __ASM_MACH_AR71XX_REGS_H */ diff --git a/target/linux/ath79/image/lzma-loader/src/board.c b/target/linux/ath79/image/lzma-loader/src/board.c index 2f4dd6b1f6..7b1e110ee2 100644 --- a/target/linux/ath79/image/lzma-loader/src/board.c +++ b/target/linux/ath79/image/lzma-loader/src/board.c @@ -10,6 +10,7 @@ #include <stddef.h> #include "config.h" +#include "printf.h" #include "ar71xx_regs.h" #define READREG(r) *(volatile unsigned int *)(r) @@ -50,7 +51,139 @@ static void tlwr1043nd_init(void) static inline void tlwr1043nd_init(void) {} #endif +#ifdef CONFIG_BOARD_MERAKI_MR18 + +static int mr18_extract_sgmii_res_cal(void) +{ + unsigned int base; + unsigned int reversed_sgmii_value; + + unsigned int otp_value, otp_per_val, rbias_per, read_data; + unsigned int rbias_pos_or_neg; + unsigned int sgmii_res_cal_value; + int res_cal_val; + + base = KSEG1ADDR(QCA955X_OTP_BASE); + + WRITEREG(base + QCA955X_OTP_REG_INTF2, 0x7d); + WRITEREG(base + QCA955X_OTP_REG_LDO_CTRL, 0x00); + + while (READREG(base + QCA955X_OTP_REG_LDO_STATUS) & + QCA955X_OTP_LDO_STATUS_POWER_ON) + ; + + READREG(base + QCA955X_OTP_REG_MEM_0 + 4); + + while (!(READREG(base + QCA955X_OTP_REG_STATUS0) & + QCA955X_OTP_STATUS0_EFUSE_VALID)) + ; + + read_data = READREG(base + QCA955X_OTP_REG_STATUS1); + + if (!(read_data & 0x1fff)) + return 0; + + if (read_data & 0x00001000) + otp_value = (read_data & 0xfc0) >> 6; + else + otp_value = read_data & 0x3f; + + if (otp_value > 31) { + otp_per_val = 63 - otp_value; + rbias_pos_or_neg = 1; + } else { + otp_per_val = otp_value; + rbias_pos_or_neg = 0; + } + + rbias_per = otp_per_val * 15; + + if (rbias_pos_or_neg == 1) + res_cal_val = (rbias_per + 34) / 21; + else if (rbias_per > 34) + res_cal_val = -((rbias_per - 34) / 21); + else + res_cal_val = (34 - rbias_per) / 21; + + sgmii_res_cal_value = (8 + res_cal_val) & 0xf; + + reversed_sgmii_value = (sgmii_res_cal_value & 8) >> 3; + reversed_sgmii_value |= (sgmii_res_cal_value & 4) >> 1; + reversed_sgmii_value |= (sgmii_res_cal_value & 2) << 1; + reversed_sgmii_value |= (sgmii_res_cal_value & 1) << 3; + printf("SGMII cal value = 0x%x\n", reversed_sgmii_value); + return reversed_sgmii_value; +} + +#define QCA955X_SGMII_SERDES_RES_CALIBRATION BIT(23) +#define QCA955X_SGMII_SERDES_RES_CALIBRATION_MASK 0xf +#define QCA955X_SGMII_SERDES_RES_CALIBRATION_SHIFT 23 +#define QCA955X_SGMII_SERDES_LOCK_DETECT_STATUS BIT(15) +#define QCA955X_PLL_ETH_SGMII_SERDES_LOCK_DETECT BIT(2) +#define QCA955X_PLL_ETH_SGMII_SERDES_PLL_REFCLK BIT(1) +#define QCA955X_PLL_ETH_SGMII_SERDES_EN_PLL BIT(0) +#define QCA955X_PLL_CLK_CTRL_REG 0x08 +#define QCA955X_PLL_ETH_XMII_CONTROL_REG 0x28 +#define QCA955X_PLL_ETH_SGMII_CONTROL_REG 0x48 +#define QCA955X_PLL_ETH_SGMII_SERDES_REG 0x4c + +static void qca955x_device_reset_clear(unsigned int mask) +{ + unsigned int t, reg; + + reg = KSEG1ADDR(AR71XX_RESET_BASE + + QCA955X_RESET_REG_RESET_MODULE); + + t = READREG(reg); + WRITEREG(reg, t & ~mask); +} + +static void mr18_setup_qca955x_eth_serdes_cal(unsigned int sgmii_value) +{ + unsigned int ethbase, pllbase, t; + + ethbase = KSEG1ADDR(QCA955X_GMAC_BASE); + pllbase = KSEG1ADDR(AR71XX_PLL_BASE); + + /* To Check the locking of the SGMII PLL */ + t = READREG(ethbase + QCA955X_GMAC_REG_SGMII_SERDES); + t &= ~(QCA955X_SGMII_SERDES_RES_CALIBRATION_MASK << + QCA955X_SGMII_SERDES_RES_CALIBRATION_SHIFT); + t |= (sgmii_value & QCA955X_SGMII_SERDES_RES_CALIBRATION_MASK) << + QCA955X_SGMII_SERDES_RES_CALIBRATION_SHIFT; + WRITEREG(ethbase + QCA955X_GMAC_REG_SGMII_SERDES, t); + + WRITEREG(pllbase + QCA955X_PLL_ETH_SGMII_SERDES_REG, + QCA955X_PLL_ETH_SGMII_SERDES_LOCK_DETECT | + QCA955X_PLL_ETH_SGMII_SERDES_PLL_REFCLK | + QCA955X_PLL_ETH_SGMII_SERDES_EN_PLL) + ; + + qca955x_device_reset_clear(QCA955X_RESET_SGMII_ANALOG); + qca955x_device_reset_clear(QCA955X_RESET_SGMII); + + while (!(READREG(ethbase + QCA955X_GMAC_REG_SGMII_SERDES) & + QCA955X_SGMII_SERDES_LOCK_DETECT_STATUS)) + ; +} + +static inline void mr18_init(void) +{ + int res; + + printf("Meraki MR18\n"); + + res = mr18_extract_sgmii_res_cal(); + if (res >= 0) + mr18_setup_qca955x_eth_serdes_cal(res); + +} +#else +static inline void mr18_init(void) { } +#endif + void board_init(void) { tlwr1043nd_init(); + mr18_init(); } |