2 * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
4 * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published
8 * by the Free Software Foundation.
14 #include "ar71xx_regs.h"
16 #define READREG(r) *(volatile unsigned int *)(r)
17 #define WRITEREG(r,v) *(volatile unsigned int *)(r) = v
19 #define KSEG1ADDR(_x) (((_x) & 0x1fffffff) | 0xa0000000)
21 #define UART_BASE 0xb8020000
26 #define UART_LSR_THRE 0x20
28 #define UART_READ(r) READREG(UART_BASE + 4 * (r))
29 #define UART_WRITE(r,v) WRITEREG(UART_BASE + 4 * (r), (v))
31 void board_putc(int ch
)
33 while (((UART_READ(UART_LSR
)) & UART_LSR_THRE
) == 0);
34 UART_WRITE(UART_TX
, ch
);
35 while (((UART_READ(UART_LSR
)) & UART_LSR_THRE
) == 0);
38 #ifdef CONFIG_BOARD_TL_WR1043ND_V1
39 static void tlwr1043nd_init(void)
41 unsigned int reg
= KSEG1ADDR(AR71XX_RESET_BASE
);
44 t
= READREG(reg
+ AR913X_RESET_REG_RESET_MODULE
);
45 t
|= AR71XX_RESET_GE0_PHY
;
46 WRITEREG(reg
+ AR913X_RESET_REG_RESET_MODULE
, t
);
48 t
= READREG(reg
+ AR913X_RESET_REG_RESET_MODULE
);
51 static inline void tlwr1043nd_init(void) {}
54 #ifdef CONFIG_BOARD_MERAKI_MR18
56 static int mr18_extract_sgmii_res_cal(void)
59 unsigned int reversed_sgmii_value
;
61 unsigned int otp_value
, otp_per_val
, rbias_per
, read_data
;
62 unsigned int rbias_pos_or_neg
;
63 unsigned int sgmii_res_cal_value
;
66 base
= KSEG1ADDR(QCA955X_OTP_BASE
);
68 WRITEREG(base
+ QCA955X_OTP_REG_INTF2
, 0x7d);
69 WRITEREG(base
+ QCA955X_OTP_REG_LDO_CTRL
, 0x00);
71 while (READREG(base
+ QCA955X_OTP_REG_LDO_STATUS
) &
72 QCA955X_OTP_LDO_STATUS_POWER_ON
)
75 READREG(base
+ QCA955X_OTP_REG_MEM_0
+ 4);
77 while (!(READREG(base
+ QCA955X_OTP_REG_STATUS0
) &
78 QCA955X_OTP_STATUS0_EFUSE_VALID
))
81 read_data
= READREG(base
+ QCA955X_OTP_REG_STATUS1
);
83 if (!(read_data
& 0x1fff))
86 if (read_data
& 0x00001000)
87 otp_value
= (read_data
& 0xfc0) >> 6;
89 otp_value
= read_data
& 0x3f;
92 otp_per_val
= 63 - otp_value
;
95 otp_per_val
= otp_value
;
99 rbias_per
= otp_per_val
* 15;
101 if (rbias_pos_or_neg
== 1)
102 res_cal_val
= (rbias_per
+ 34) / 21;
103 else if (rbias_per
> 34)
104 res_cal_val
= -((rbias_per
- 34) / 21);
106 res_cal_val
= (34 - rbias_per
) / 21;
108 sgmii_res_cal_value
= (8 + res_cal_val
) & 0xf;
110 reversed_sgmii_value
= (sgmii_res_cal_value
& 8) >> 3;
111 reversed_sgmii_value
|= (sgmii_res_cal_value
& 4) >> 1;
112 reversed_sgmii_value
|= (sgmii_res_cal_value
& 2) << 1;
113 reversed_sgmii_value
|= (sgmii_res_cal_value
& 1) << 3;
114 printf("SGMII cal value = 0x%x\n", reversed_sgmii_value
);
115 return reversed_sgmii_value
;
118 #define QCA955X_SGMII_SERDES_RES_CALIBRATION BIT(23)
119 #define QCA955X_SGMII_SERDES_RES_CALIBRATION_MASK 0xf
120 #define QCA955X_SGMII_SERDES_RES_CALIBRATION_SHIFT 23
121 #define QCA955X_SGMII_SERDES_LOCK_DETECT_STATUS BIT(15)
122 #define QCA955X_PLL_ETH_SGMII_SERDES_LOCK_DETECT BIT(2)
123 #define QCA955X_PLL_ETH_SGMII_SERDES_PLL_REFCLK BIT(1)
124 #define QCA955X_PLL_ETH_SGMII_SERDES_EN_PLL BIT(0)
125 #define QCA955X_PLL_CLK_CTRL_REG 0x08
126 #define QCA955X_PLL_ETH_XMII_CONTROL_REG 0x28
127 #define QCA955X_PLL_ETH_SGMII_CONTROL_REG 0x48
128 #define QCA955X_PLL_ETH_SGMII_SERDES_REG 0x4c
130 static void qca955x_device_reset_clear(unsigned int mask
)
134 reg
= KSEG1ADDR(AR71XX_RESET_BASE
+
135 QCA955X_RESET_REG_RESET_MODULE
);
138 WRITEREG(reg
, t
& ~mask
);
141 static void mr18_setup_qca955x_eth_serdes_cal(unsigned int sgmii_value
)
143 unsigned int ethbase
, pllbase
, t
;
145 ethbase
= KSEG1ADDR(QCA955X_GMAC_BASE
);
146 pllbase
= KSEG1ADDR(AR71XX_PLL_BASE
);
148 /* To Check the locking of the SGMII PLL */
149 t
= READREG(ethbase
+ QCA955X_GMAC_REG_SGMII_SERDES
);
150 t
&= ~(QCA955X_SGMII_SERDES_RES_CALIBRATION_MASK
<<
151 QCA955X_SGMII_SERDES_RES_CALIBRATION_SHIFT
);
152 t
|= (sgmii_value
& QCA955X_SGMII_SERDES_RES_CALIBRATION_MASK
) <<
153 QCA955X_SGMII_SERDES_RES_CALIBRATION_SHIFT
;
154 WRITEREG(ethbase
+ QCA955X_GMAC_REG_SGMII_SERDES
, t
);
156 WRITEREG(pllbase
+ QCA955X_PLL_ETH_SGMII_SERDES_REG
,
157 QCA955X_PLL_ETH_SGMII_SERDES_LOCK_DETECT
|
158 QCA955X_PLL_ETH_SGMII_SERDES_PLL_REFCLK
|
159 QCA955X_PLL_ETH_SGMII_SERDES_EN_PLL
)
162 qca955x_device_reset_clear(QCA955X_RESET_SGMII_ANALOG
);
163 qca955x_device_reset_clear(QCA955X_RESET_SGMII
);
165 while (!(READREG(ethbase
+ QCA955X_GMAC_REG_SGMII_SERDES
) &
166 QCA955X_SGMII_SERDES_LOCK_DETECT_STATUS
))
170 static inline void mr18_init(void)
174 printf("Meraki MR18\n");
176 res
= mr18_extract_sgmii_res_cal();
178 mr18_setup_qca955x_eth_serdes_cal(res
);
182 static inline void mr18_init(void) { }
185 #ifdef CONFIG_BOARD_HUAWEI_AP5030DN
186 static inline void ap5030dn_init(void)
188 const unsigned int ap5030dn_watchdog_gpio
= 15;
189 unsigned int gpiobase
, reg
;
191 gpiobase
= KSEG1ADDR(AR71XX_GPIO_BASE
);
193 printf("Huawei AP5030DN\n");
195 reg
= READREG(gpiobase
+ AR71XX_GPIO_REG_OE
);
196 WRITEREG(gpiobase
+ AR71XX_GPIO_REG_OE
,
197 reg
& ~(1 << ap5030dn_watchdog_gpio
));
199 /* Set GPIO15 MUX to output CLK_OBS5 (= CPU_CLK/4)
200 * to keep the watchdog happy until wdt-gpio takes over
202 reg
= READREG(gpiobase
+ AR934X_GPIO_REG_OUT_FUNC3
);
203 WRITEREG(gpiobase
+ AR934X_GPIO_REG_OUT_FUNC3
,
204 reg
| (QCA955X_GPIO_OUTSEL_CLK_OBS5
<< 24));
207 static inline void ap5030dn_init(void) { }
210 void board_init(void)