1/* 2 * Cisco Meraki MR18 board support 3 * 4 * Copyright (C) 2015 Chris Blake <chrisrblake93@gmail.com> 5 * Copyright (C) 2015 Christian Lamparter <chunkeey@googlemail.com> 6 * Copyright (C) 2015 Thomas Hebb <tommyhebb@gmail.com> 7 * 8 * Based on Cisco Meraki GPL Release r23-20150601 MR18 Device Config 9 * 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License version 2 as published 12 * by the Free Software Foundation. 13 */ 14#include <linux/platform_device.h> 15#include <linux/ath9k_platform.h> 16#include <linux/platform/ar934x_nfc.h> 17#include <linux/platform_data/phy-at803x.h> 18 19#include <asm/mach-ath79/ath79.h> 20#include <asm/mach-ath79/ar71xx_regs.h> 21 22#include <linux/leds-nu801.h> 23#include <linux/pci.h> 24 25#include "common.h" 26#include "dev-eth.h" 27#include "pci.h" 28#include "dev-gpio-buttons.h" 29#include "dev-leds-gpio.h" 30#include "dev-nfc.h" 31#include "dev-wmac.h" 32#include "machtypes.h" 33 34#define MR18_GPIO_LED_POWER_WHITE 18 35#define MR18_GPIO_LED_POWER_ORANGE 21 36 37#define MR18_GPIO_BTN_RESET 17 38#define MR18_KEYS_POLL_INTERVAL 20 /* msecs */ 39#define MR18_KEYS_DEBOUNCE_INTERVAL (3 * MR18_KEYS_POLL_INTERVAL) 40 41#define MR18_WAN_PHYADDR 3 42 43/* used for eth calibration */ 44#define MR18_OTP_BASE (AR71XX_APB_BASE + 0x130000) 45#define MR18_OTP_SIZE (0x2000) /* just a guess */ 46#define MR18_OTP_MEM_0_REG (0x0000) 47#define MR18_OTP_INTF2_REG (0x1008) 48#define MR18_OTP_STATUS0_REG (0x1018) 49#define MR18_OTP_STATUS0_EFUSE_VALID BIT(2) 50 51#define MR18_OTP_STATUS1_REG (0x101c) 52#define MR18_OTP_LDO_CTRL_REG (0x1024) 53#define MR18_OTP_LDO_STATUS_REG (0x102c) 54#define MR18_OTP_LDO_STATUS_POWER_ON BIT(0) 55 56static struct gpio_led MR18_leds_gpio[] __initdata = { 57 { 58 .name = "mr18:white:power", 59 .gpio = MR18_GPIO_LED_POWER_WHITE, 60 .active_low = 1, 61 }, { 62 .name = "mr18:orange:power", 63 .gpio = MR18_GPIO_LED_POWER_ORANGE, 64 .active_low = 0, 65 }, 66}; 67 68static struct gpio_keys_button MR18_gpio_keys[] __initdata = { 69 { 70 .desc = "reset", 71 .type = EV_KEY, 72 .code = KEY_RESTART, 73 .debounce_interval = MR18_KEYS_DEBOUNCE_INTERVAL, 74 .gpio = MR18_GPIO_BTN_RESET, 75 .active_low = 1, 76 }, 77}; 78 79static struct led_nu801_template tricolor_led_template = { 80 .device_name = "mr18", 81 .name = "tricolor", 82 .num_leds = 1, 83 .cki = 11, 84 .sdi = 12, 85 .lei = -1, 86 .ndelay = 500, 87 .init_brightness = { 88 LED_OFF, 89 LED_OFF, 90 LED_OFF, 91 }, 92 .default_trigger = "none", 93 .led_colors = { "red", "green", "blue" }, 94}; 95 96static struct led_nu801_platform_data tricolor_led_data = { 97 .num_controllers = 1, 98 .template = &tricolor_led_template, 99}; 100 101static struct platform_device tricolor_leds = { 102 .name = "leds-nu801", 103 .id = -1, 104 .dev.platform_data = &tricolor_led_data, 105}; 106 107static int mr18_extract_sgmii_res_cal(void) 108{ 109 void __iomem *base; 110 unsigned int reversed_sgmii_value; 111 112 unsigned int otp_value, otp_per_val, rbias_per, read_data; 113 unsigned int rbias_pos_or_neg; 114 unsigned int sgmii_res_cal_value; 115 int res_cal_val; 116 117 base = ioremap_nocache(MR18_OTP_BASE, MR18_OTP_SIZE); 118 if (!base) 119 return -EIO; 120 121 __raw_writel(0x7d, base + MR18_OTP_INTF2_REG); 122 __raw_writel(0x00, base + MR18_OTP_LDO_CTRL_REG); 123 124 while (__raw_readl(base + MR18_OTP_LDO_STATUS_REG) & 125 MR18_OTP_LDO_STATUS_POWER_ON); 126 127 __raw_readl(base + MR18_OTP_MEM_0_REG + 4); 128 129 while (!(__raw_readl(base + MR18_OTP_STATUS0_REG) & 130 MR18_OTP_STATUS0_EFUSE_VALID)); 131 132 read_data = __raw_readl(base + MR18_OTP_STATUS1_REG); 133 134 iounmap(base); 135 136 if (!(read_data & 0x1fff)) 137 return -ENODEV; 138 139 if (read_data & 0x00001000) 140 otp_value = (read_data & 0xfc0) >> 6; 141 else 142 otp_value = read_data & 0x3f; 143 144 if (otp_value > 31) { 145 otp_per_val = 63 - otp_value; 146 rbias_pos_or_neg = 1; 147 } else { 148 otp_per_val = otp_value; 149 rbias_pos_or_neg = 0; 150 } 151 152 rbias_per = otp_per_val * 15; 153 154 if (rbias_pos_or_neg == 1) 155 res_cal_val = (rbias_per + 34) / 21; 156 else if (rbias_per > 34) 157 res_cal_val = -((rbias_per - 34) / 21); 158 else 159 res_cal_val = (34 - rbias_per) / 21; 160 161 sgmii_res_cal_value = (8 + res_cal_val) & 0xf; 162 163 reversed_sgmii_value = (sgmii_res_cal_value & 8) >> 3; 164 reversed_sgmii_value |= (sgmii_res_cal_value & 4) >> 1; 165 reversed_sgmii_value |= (sgmii_res_cal_value & 2) << 1; 166 reversed_sgmii_value |= (sgmii_res_cal_value & 1) << 3; 167 printk(KERN_INFO "SGMII cal value = 0x%x\n", reversed_sgmii_value); 168 return reversed_sgmii_value; 169} 170 171#define QCA955X_PLL_ETH_SGMII_SERDES_REG 0x004c 172#define QCA955X_PLL_ETH_SGMII_SERDES_LOCK_DETECT BIT(2) 173#define QCA955X_PLL_ETH_SGMII_SERDES_PLL_REFCLK BIT(1) 174#define QCA955X_PLL_ETH_SGMII_SERDES_EN_PLL BIT(0) 175 176#define QCA955X_GMAC_REG_SGMII_SERDES 0x0018 177#define QCA955X_SGMII_SERDES_RES_CALIBRATION BIT(23) 178#define QCA955X_SGMII_SERDES_RES_CALIBRATION_MASK 0xf 179#define QCA955X_SGMII_SERDES_RES_CALIBRATION_SHIFT 23 180#define QCA955X_SGMII_SERDES_LOCK_DETECT_STATUS BIT(15) 181 182static void mr18_setup_qca955x_eth_serdes_cal(unsigned int sgmii_value) 183{ 184 void __iomem *ethbase, *pllbase; 185 u32 t; 186 187 ethbase = ioremap_nocache(QCA955X_GMAC_BASE, QCA955X_GMAC_SIZE); 188 pllbase = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE); 189 190 /* To Check the locking of the SGMII PLL */ 191 t = __raw_readl(ethbase + QCA955X_GMAC_REG_SGMII_SERDES); 192 t &= ~(QCA955X_SGMII_SERDES_RES_CALIBRATION_MASK << 193 QCA955X_SGMII_SERDES_RES_CALIBRATION_SHIFT); 194 t |= (sgmii_value & QCA955X_SGMII_SERDES_RES_CALIBRATION_MASK) << 195 QCA955X_SGMII_SERDES_RES_CALIBRATION_SHIFT; 196 __raw_writel(t, ethbase + QCA955X_GMAC_REG_SGMII_SERDES); 197 198 __raw_writel(QCA955X_PLL_ETH_SGMII_SERDES_LOCK_DETECT | 199 QCA955X_PLL_ETH_SGMII_SERDES_PLL_REFCLK | 200 QCA955X_PLL_ETH_SGMII_SERDES_EN_PLL, 201 pllbase + QCA955X_PLL_ETH_SGMII_SERDES_REG); 202 203 ath79_device_reset_clear(QCA955X_RESET_SGMII_ANALOG); 204 ath79_device_reset_clear(QCA955X_RESET_SGMII); 205 206 while (!(__raw_readl(ethbase + QCA955X_GMAC_REG_SGMII_SERDES) & 207 QCA955X_SGMII_SERDES_LOCK_DETECT_STATUS)); 208 209 iounmap(ethbase); 210 iounmap(pllbase); 211} 212 213static struct ath9k_platform_data pci_main_wifi_data = { 214 .led_pin = -1, 215}; 216static struct ath9k_platform_data pci_scan_wifi_data = { 217 .led_pin = -1, 218}; 219 220static int mr18_dual_pci_plat_dev_init(struct pci_dev *dev) 221{ 222 /* The PCIE devices are attached to different busses but they 223 * both share the same slot number. Checking the PCI_SLOT vals 224 * does not work. 225 */ 226 switch (dev->bus->number) { 227 case 0: 228 dev->dev.platform_data = &pci_main_wifi_data; 229 break; 230 case 1: 231 dev->dev.platform_data = &pci_scan_wifi_data; 232 break; 233 } 234 235 return 0; 236} 237 238static void __init mr18_setup(void) 239{ 240 int res; 241 242 /* NAND */ 243 ath79_nfc_set_ecc_mode(AR934X_NFC_ECC_SOFT_BCH); 244 ath79_register_nfc(); 245 246 /* even though, the PHY is connected via RGMII, 247 * the SGMII/SERDES PLLs need to be calibrated and locked. 248 * Or else, the PHY won't be working for this platfrom. 249 * 250 * Figuring this out took such a long time, that we want to 251 * point this quirk out, before someone wants to remove it. 252 */ 253 res = mr18_extract_sgmii_res_cal(); 254 if (res >= 0) { 255 /* Setup SoC Eth Config */ 256 ath79_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN | 257 (3 << QCA955X_ETH_CFG_RXD_DELAY_SHIFT) | 258 (3 << QCA955X_ETH_CFG_RDV_DELAY_SHIFT)); 259 260 /* MDIO Interface */ 261 ath79_register_mdio(0, 0x0); 262 263 mr18_setup_qca955x_eth_serdes_cal(res); 264 265 /* GMAC0 is connected to an Atheros AR8035-A */ 266 ath79_init_mac(ath79_eth0_data.mac_addr, NULL, 0); 267 ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev; 268 ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; 269 ath79_eth0_data.phy_mask = BIT(MR18_WAN_PHYADDR); 270 ath79_eth0_pll_data.pll_1000 = 0xa6000000; 271 ath79_eth0_pll_data.pll_100 = 0xa0000101; 272 ath79_eth0_pll_data.pll_10 = 0x80001313; 273 ath79_register_eth(0); 274 } else { 275 printk(KERN_ERR "failed to read EFUSE for ethernet cal\n"); 276 } 277 278 /* LEDs and Buttons */ 279 platform_device_register(&tricolor_leds); 280 ath79_register_leds_gpio(-1, ARRAY_SIZE(MR18_leds_gpio), 281 MR18_leds_gpio); 282 ath79_register_gpio_keys_polled(-1, MR18_KEYS_POLL_INTERVAL, 283 ARRAY_SIZE(MR18_gpio_keys), 284 MR18_gpio_keys); 285 286 /* Clear RTC reset (Needed by SoC WiFi) */ 287 ath79_device_reset_clear(QCA955X_RESET_RTC); 288 289 /* WiFi */ 290 ath79_register_wmac_simple(); 291 292 pci_main_wifi_data.eeprom_name = "pci_wmac0.eeprom"; 293 pci_scan_wifi_data.eeprom_name = "pci_wmac1.eeprom"; 294 ath79_pci_set_plat_dev_init(mr18_dual_pci_plat_dev_init); 295 ath79_register_pci(); 296} 297MIPS_MACHINE(ATH79_MACH_MR18, "MR18", "Meraki MR18", mr18_setup); 298