aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/ath79/image
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/ath79/image')
-rw-r--r--target/linux/ath79/image/lzma-loader/src/ar71xx_regs.h17
-rw-r--r--target/linux/ath79/image/lzma-loader/src/board.c133
-rw-r--r--target/linux/ath79/image/nand.mk25
3 files changed, 175 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();
}
diff --git a/target/linux/ath79/image/nand.mk b/target/linux/ath79/image/nand.mk
index 10a5485010..4f34521a50 100644
--- a/target/linux/ath79/image/nand.mk
+++ b/target/linux/ath79/image/nand.mk
@@ -11,6 +11,14 @@ define Build/dongwon-header
mv $@.tmp $@
endef
+define Build/meraki-header
+ -$(STAGING_DIR_HOST)/bin/mkmerakifw \
+ -B $(1) -s \
+ -i $@ \
+ -o $@.new
+ @mv $@.new $@
+endef
+
# attention: only zlib compression is allowed for the boot fs
define Build/zyxel-buildkerneljffs
mkdir -p $@.tmp/boot
@@ -260,6 +268,23 @@ define Device/linksys_ea4500-v3
endef
TARGET_DEVICES += linksys_ea4500-v3
+define Device/meraki_mr18
+ SOC := qca9557
+ DEVICE_VENDOR := Meraki
+ DEVICE_MODEL := MR18
+ DEVICE_PACKAGES := kmod-spi-gpio nu801
+ KERNEL_SIZE := 8m
+ BLOCKSIZE := 128k
+ PAGESIZE := 2048
+ LOADER_TYPE := bin
+ KERNEL := kernel-bin | append-dtb | lzma | loader-kernel | meraki-header MR18
+# Initramfs-build fails due to size issues
+# KERNEL_INITRAMFS := $$(KERNEL)
+ KERNEL_INITRAMFS :=
+ IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata
+endef
+TARGET_DEVICES += meraki_mr18
+
# fake rootfs is mandatory, pad-offset 64 equals (1 * uimage_header)
define Device/netgear_ath79_nand
DEVICE_VENDOR := NETGEAR