/* * Qualcomm Atheros AP135 reference board support * * Copyright (c) 2012 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. */ #include #include #include #include #include #include #include #include #include #include #include "common.h" #include "pci.h" #include "dev-ap9x-pci.h" #include "dev-usb.h" #include "dev-nand.h" #include "dev-wmac.h" #include "machtypes.h" /* #define AVM_PMU_DEBUG */ static bool __init has_usb(void) { struct device_node *node = of_find_node_by_name(NULL, "usb"); if (node) { of_node_put(node); return true; } return false; } static void __init avm_usb_setup(void) { /* Only initialize USB when declaed in the DTS */ if (!has_usb()) { if (soc_is_qcn550x()) ath_reg_rmw_clear(ATH_RST_CLKGAT_EN, ATH_RST_CLKGAT_EN_USB1); return; } #if defined(CONFIG_USB) || defined(CONFIG_USB_MODULE) /* Bring USB out of reset */ ath79_device_reset_clear(QCA953X_RESET_USB_PHY | QCA953X_RESET_USB_PHY_ANALOG | QCA953X_RESET_USB_HOST | QCA953X_RESET_USB_PHY_PLL_PWD_EXT); if (soc_is_qca956x()) { unsigned int value; /* Configure USB Reference Clock */ value = ath_reg_rd(ATH_PLL_SWITCH_CLOCK_CONTROL); value &= ~(SWITCH_CLOCK_SPARE_USB_REFCLK_FREQ_SEL_MASK); if ((ath79_reset_rr(QCA956X_RESET_REG_BOOTSTRAP) & QCA956X_BOOTSTRAP_REF_CLK_40)) value |= SWITCH_CLOCK_SPARE_USB_REFCLK_FREQ_SEL_SET(5); else value |= SWITCH_CLOCK_SPARE_USB_REFCLK_FREQ_SEL_SET(2) | SWITCH_CLOCK_SPARE_SWITCHCLK_SEL_SET(1); value |= ATH_PLL_SWITCH_CLOCK_CONTROL_OEN_CLK125M_SEL_SET(1) | ATH_PLL_SWITCH_CLOCK_CONTROL_EN_PLL_TOP_SET(1) | ATH_PLL_SWITCH_CLOCK_CONTROL_MDIO_CLK_SEL1_1_SET(1); ath_reg_wr(ATH_PLL_SWITCH_CLOCK_CONTROL, value); pr_info("[avm] Enabled USB clock\n"); } #endif } static bool __init has_pci(void) { #if IS_ENABLED(CONFIG_PCI) struct device_node *node = of_find_node_by_name(NULL, "pci"); if (node) { of_node_put(node); return true; } #endif return false; } static void __init ar724x_pci_pll_init(void) { #if defined(CONFIG_PCI) /* * Initialize PCIE PLL and get it out of RESET * reg = 0x18050010 */ #if defined(CONFIG_SOC_AR724X) unsigned int pcie_pll_div = 5; /*--- MULT ---*/ unsigned int pcie_pll_revdif = 2; ath_reg_wr(ATH_PCIE_PLL_CONFIG, (0x02050000 | pcie_pll_div | (pcie_pll_revdif << 10))); mdelay(100); ath_reg_wr(ATH_PCIE_PLL_CONFIG, (0x00050000 | pcie_pll_div | (pcie_pll_revdif << 10))); mdelay(100); ath_reg_wr(ATH_PCIE_PLL_CONFIG, (0x00040000 | pcie_pll_div | (pcie_pll_revdif << 10))); mdelay(100); #else /*--- #if defined(CONFIG_SOC_AR724X) ---*/ // common for rc1 and rc2 #if defined(CONFIG_SOC_QCA953X) || defined(CONFIG_SOC_QCA956X) || defined(CONFIG_SOC_QCN550X) #if defined(CONFIG_SOC_QCA956X) || defined(CONFIG_SOC_QCN550X) ath_reg_rmw_set(ATH_PCIE_PHY_REG1, ATH_PCIE_PHY_REG1_S_SET(ATH_PCIE_PHY_REG1_S_RESET)); #endif ath_reg_wr_nf(ATH_PLL_PCIE_PLL_DITHER_DIV_MAX, #if !defined(CONFIG_SOC_QCA956X) || defined(CONFIG_SOC_QCN550X) PCIE_PLL_DITHER_DIV_MAX_EN_DITHER_SET(0x1) | #endif PCIE_PLL_DITHER_DIV_MAX_USE_MAX_SET(0x1) | PCIE_PLL_DITHER_DIV_MAX_DIV_MAX_INT_SET(0x17) | PCIE_PLL_DITHER_DIV_MAX_DIV_MAX_FRAC_SET(0x3fff)); ath_reg_wr_nf(ATH_PLL_PCIE_PLL_DITHER_DIV_MIN, PCIE_PLL_DITHER_DIV_MIN_DIV_MIN_FRAC_SET(0x3f84)| PCIE_PLL_DITHER_DIV_MIN_DIV_MIN_INT_SET(0x17)); #else ath_reg_wr_nf(ATH_PLL_PCIE_PLL_DITHER_DIV_MAX, PCIE_PLL_DITHER_DIV_MAX_EN_DITHER_SET(0x1) | PCIE_PLL_DITHER_DIV_MAX_USE_MAX_SET(0x1) | PCIE_PLL_DITHER_DIV_MAX_DIV_MAX_INT_SET(0x14) | PCIE_PLL_DITHER_DIV_MAX_DIV_MAX_FRAC_SET(0x3ff)); ath_reg_wr_nf(ATH_PLL_PCIE_PLL_DITHER_DIV_MIN, PCIE_PLL_DITHER_DIV_MIN_DIV_MIN_INT_SET(0x14)); #endif #if defined(CONFIG_SOC_QCA956X) || defined(CONFIG_SOC_QCN550X) pr_debug("Power up PLL with outdiv = 0 then switch to 3\n"); ath_reg_wr(PCIE_DPLL3_ADDRESS, PCIE_DPLL3_LOCAL_PLL_PWD_SET(0x1)); ath_reg_rmw_clear(ATH_PCIE_PLL_CONFIG, PCIE_PLL_CONFIG_PLLPWD_SET(1)); ath_reg_rmw_clear(ATH_PCIE_PLL_CONFIG, PCIE_PLL_CONFIG_BYPASS_SET(1)); ath_reg_wr(PCIE_DPLL1_ADDRESS, PCIE_DPLL1_REFDIV_SET(0x1) | PCIE_DPLL1_NINT_SET(0x18)); ath_reg_wr(PCIe_DPLL2_ADDRESS, PCIe_DPLL2_LOCAL_PLL_SET(0x1) | PCIe_DPLL2_KD_SET(0x4) | PCIe_DPLL2_PLL_PWD_SET(0x1) | PCIe_DPLL2_PHASE_SHIFT_SET(0x6)); ath_reg_wr(PCIE_DPLL3_ADDRESS, PCIE_DPLL3_RESET); ath_reg_wr(PCIe_DPLL2_ADDRESS, PCIe_DPLL2_LOCAL_PLL_SET(0x1) | PCIe_DPLL2_KD_SET(0x4) | PCIe_DPLL2_PLL_PWD_SET(0x1) | PCIe_DPLL2_OUTDIV_SET(0x3) | PCIe_DPLL2_PHASE_SHIFT_SET(0x6)); #else ath_reg_wr_nf(ATH_PCIE_PLL_CONFIG, PCIE_PLL_CONFIG_REFDIV_SET(1) | PCIE_PLL_CONFIG_BYPASS_SET(1) | PCIE_PLL_CONFIG_PLLPWD_SET(1)); mdelay(10); ath_reg_rmw_clear(ATH_PCIE_PLL_CONFIG, PCIE_PLL_CONFIG_PLLPWD_SET(1)); mdelay(1); ath_reg_rmw_clear(ATH_PCIE_PLL_CONFIG, PCIE_PLL_CONFIG_BYPASS_SET(1)); #endif mdelay(1); #endif /*--- #else ---*/ /*--- #if defined(CONFIG_SOC_AR724X) ---*/ #endif /*--- defined(CONFIG_PCI) ---*/ } static void __init avm_pmu_setup(void) { u32 *base; int count, i, val, ret; struct device_node *node = of_find_node_by_name(NULL, "avm_pmu"); if (!node) return; count = of_property_count_elems_of_size(node, "reg", 4); /* Does not exist, therefore we don't want to set anything */ if (count == -EINVAL) return; BUG_ON(count < 0); for (i = 0; i < count; i += 2) { ret = of_property_read_u32_index(node, "reg", i, (u32 *)&base); BUG_ON(ret < 0); ret = of_property_read_u32_index(node, "reg", i + 1, &val); BUG_ON(ret < 0); pr_info("[avm_pmu] Set reg %p to 0x%08x\n", base, val); ath_reg_wr(base, val); } } static void __init avm_generic_setup(void) { ath79_ddr_ctrl_init(); avm_usb_setup(); avm_pmu_setup(); if (has_pci()) ar724x_pci_pll_init(); else if (soc_is_qcn550x()) { ath_reg_rmw_clear(ATH_RST_CLKGAT_EN, ATH_RST_CLKGAT_EN_PCIE_RC | ATH_RST_CLKGAT_EN_CLK100_PCIE_RC); ath_reg_wr(ATH_PCIE_PHY_REG1, 0x1061060e); ath_reg_wr(ATH_PCIE_EP_PHY_REG1, 0x1061060e); } else if (soc_is_ar934x()) { /* Disable PCIe on wasp */ pr_err("[%s] disable PCIe\n", __func__); /*--- change PCIE to reduce power about 18mA ---*/ ath_reg_wr(ATH_PCIE_PHY_REG1, 0x1061060e); ath_reg_wr(ATH_PCIE_EP_PHY_REG1, 0x1061060e); } } MIPS_MACHINE(ATH79_MACH_AVM_HW190, "HW190", "AVM Powerline 546E", avm_generic_setup); MIPS_MACHINE(ATH79_MACH_AVM_HW194, "HW194", "AVM FritzRepeater 310", avm_generic_setup); MIPS_MACHINE(ATH79_MACH_AVM_HW201, "HW201", "AVM Powerline 540E", avm_generic_setup); MIPS_MACHINE(ATH79_MACH_AVM_HW205, "HW205", "AVM FritzRepeater DVB-C", avm_generic_setup); MIPS_MACHINE(ATH79_MACH_AVM_HW206, "HW206", "AVM FritzRepeater 1750E", avm_generic_setup); MIPS_MACHINE(ATH79_MACH_AVM_HW214, "HW214", "AVM FRITZ!Box 6820 LTE", avm_generic_setup); MIPS_MACHINE(ATH79_MACH_AVM_HW215, "HW215", "AVM FritzRepeater 310v2", avm_generic_setup); MIPS_MACHINE(ATH79_MACH_AVM_HW216, "HW216", "AVM FritzRepeater 1160", avm_generic_setup); MIPS_MACHINE(ATH79_MACH_AVM_HW219, "HW219", "AVM FRITZ!Box 4020", avm_generic_setup); MIPS_MACHINE(ATH79_MACH_AVM_HW222, "HW222", "AVM Powerline 1240E", avm_generic_setup); MIPS_MACHINE(ATH79_MACH_AVM_HW238, "HW238", "AVM FritzBox 7490 - Target", avm_generic_setup); MIPS_MACHINE(ATH79_MACH_AVM_HW240, "HW240", "AVM FritzRepeater 600", avm_generic_setup); MIPS_MACHINE(ATH79_MACH_AVM_HW241, "HW241", "AVM FritzRepeater 2400", avm_generic_setup); MIPS_MACHINE(ATH79_MACH_AVM_HW254, "HW254", "AVM FRITZ!Box 6820v3 LTE", avm_generic_setup); MIPS_MACHINE(ATH79_MACH_AVM_HW263, "HW263", "AVM FritzRepeater 600v2", avm_generic_setup); #ifdef AVM_PMU_DEBUG static int avm_pmu_proc_reg_write(char *string, void *reg) { int ret; unsigned long val; ret = kstrtoul(string, 0, &val); if (ret < 0) return ret; pr_err("[ath_pmu] Write 0x%08lx to %p\n", val, reg); ath_reg_wr(reg, val); return 0; } static void avm_pmu_proc_reg_read(struct seq_file *file, void *reg) { int val; pr_err("[ath_pmu] Read from %p: ", reg); val = ath_reg_rd(reg); pr_cont("0x%08x\n", val); seq_printf(file, "0x%08x\n", val); } static int __init avm_pmu_proc_init(void) { #define PATH_LEN 64 u32 *base; int i, size, ret; struct device_node *node = of_find_node_by_name(NULL, "avm_pmu"); char path[PATH_LEN]; if (!node) return 0; proc_mkdir("avm/pmu", NULL); ret = of_property_read_u32_index(node, "reg", 0, (u32 *)&base); if (ret < 0) return 0; ret = of_property_read_u32_index(node, "reg", 1, (u32 *)&size); if (ret < 0) return 0; for (i = 0; i < size / 4; i++) { snprintf(path, PATH_LEN, "avm/pmu/reg%d", i); add_simple_proc_file(path, avm_pmu_proc_reg_write, avm_pmu_proc_reg_read, base + i); } return 0; } late_initcall(avm_pmu_proc_init); #endif