aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/ath79/image/lzma-loader/src/board.c
diff options
context:
space:
mode:
authorChristian Lamparter <chunkeey@gmail.com>2021-07-30 17:59:25 +0200
committerChristian Lamparter <chunkeey@gmail.com>2023-05-14 00:08:35 +0200
commit1d49310fdb5e6febd2e7a60d55deb0adb4364307 (patch)
treef1c9b003fd8dbcf1ca46349b44cf5628567f5b8d /target/linux/ath79/image/lzma-loader/src/board.c
parentcb9ccd644bf986d5c23e40dda92576d36a1d3b1b (diff)
downloadupstream-1d49310fdb5e6febd2e7a60d55deb0adb4364307.tar.gz
upstream-1d49310fdb5e6febd2e7a60d55deb0adb4364307.tar.bz2
upstream-1d49310fdb5e6febd2e7a60d55deb0adb4364307.zip
ath79: add Cisco Meraki MR18
Specifications: SOC: Atheros/Qualcomm QCA9557-AT4A @ 720MHz RAM: 2x Winbond W9751G6KB-25 (128 MiB) FLASH: Hynix H27U1G8F2BTR-BC TSOP48 ONFI NAND (128 MiB) WIFI1: Atheros AR9550 5.0GHz (SoC) WIFI2: Atheros AR9582-AR1A 2.4GHz WIFI2: Atheros AR9582-AR1A 2.4GHz + 5GHz PHYETH: Atheros AR8035-A, 802.3af PoE capable Atheros (1x Gigabit LAN) LED: 1x Power-LED, 1 x RGB Tricolor-LED INPUT: One Reset Button UART: JP1 on PCB (Labeled UART), 3.3v-Level, 115200n8 (VCC, RX, TX, GND - VCC is closest to the boot set jumper under the console pins.) Flashing instructions: Depending on the installed firmware, there are vastly different methods to flash a MR18. These have been documented on: <https://openwrt.org/toh/meraki/mr18> Tip: Use an initramfs from a previous release and then use sysupgrade to get to the later releases. This is because the initramfs can no longer be built by the build-bots due to its size (>8 MiB). Note on that: Upgrades from AR71XX releases are possible, but they will require the force sysupgrade option ( -F ). Please backup your MR18's configuration before starting the update. The reason here is that a lot of development happend since AR71XX got removed, so I do advise to use the ( -n ) option for sysupgrade as well. This will cause the device to drop the old AR71xx configuration and make a new configurations from scratch. Note on LEDs: The LEDs has changed since AR71XX. The white LED is now used during the boot and when upgrading instead of the green tricolor LED. The technical reason is that currently the RGB-LED is brought up later by a userspace daemon. (added warning note about odm-caldata partition. remove initramfs - it's too big to be built by the bots. MerakiNAND -> meraki-header. sort nu801's targets) Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
Diffstat (limited to 'target/linux/ath79/image/lzma-loader/src/board.c')
-rw-r--r--target/linux/ath79/image/lzma-loader/src/board.c133
1 files changed, 133 insertions, 0 deletions
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();
}