| /* |
| * Copyright (c) 2013 Qualcomm Atheros, Inc. |
| * |
| * See file CREDITS for list of people who contributed to this |
| * project. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License as |
| * published by the Free Software Foundation; either version 2 of |
| * the License, or (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| * MA 02111-1307 USA |
| */ |
| |
| #include <common.h> |
| #include <command.h> |
| #include <asm/mipsregs.h> |
| #include <asm/addrspace.h> |
| #include <config.h> |
| #include <version.h> |
| #include <pci.h> |
| #include <atheros.h> |
| |
| /* |
| ** PCI controller "hose" value |
| */ |
| |
| static struct pci_controller hose; |
| |
| static int ath_local_read_config(int where, int size, uint32_t *value); |
| static int ath_local_write_config(int where, int size, uint32_t value); |
| |
| static int |
| ath_local_read_config(int where, int size, uint32_t *value) |
| { |
| *value = ath_reg_rd(ATH_PCI_CRP + where); |
| return 0; |
| } |
| |
| static int |
| ath_local_write_config(int where, int size, uint32_t value) |
| { |
| ath_reg_wr((ATH_PCI_CRP + where),value); |
| return 0; |
| } |
| |
| static int |
| ath_pci_read_config(struct pci_controller *hose, |
| pci_dev_t dev, int where, uint32_t *value) |
| { |
| *value = ath_reg_rd(ATH_PCI_DEV_CFGBASE + where); |
| return 0; |
| } |
| |
| static int |
| ath_pci_write_config(struct pci_controller *hose, |
| pci_dev_t dev, int where, uint32_t value) |
| { |
| ath_reg_wr((ATH_PCI_DEV_CFGBASE + where), value); |
| return 0; |
| } |
| |
| #ifdef PCIE2_APP_ADDRESS |
| static int |
| ath_local_read_config_rc2(int where, int size, uint32_t *value) |
| { |
| *value = ath_reg_rd(0x18250000 + where); |
| return 0; |
| } |
| |
| static int |
| ath_local_write_config_rc2(int where, int size, uint32_t value) |
| { |
| ath_reg_wr((0x18250000 + where),value); |
| return 0; |
| } |
| |
| static int |
| ath_pci_read_config_rc2(struct pci_controller *hose, |
| pci_dev_t dev, int where, uint32_t *value) |
| { |
| *value = ath_reg_rd(0xb6000000 + where); |
| return 0; |
| } |
| |
| static int |
| ath_pci_write_config_rc2(struct pci_controller *hose, |
| pci_dev_t dev, int where, uint32_t value) |
| { |
| ath_reg_wr((0xb6000000 + where), value); |
| return 0; |
| } |
| #endif |
| |
| /* |
| ** We will use the ART configuration information stored in flash to initialize |
| ** these devices as required. |
| */ |
| |
| void plat_dev_init(void) |
| { |
| u32 val; |
| u32 addr; |
| u32 BaseAddr = 0x10000000; |
| u32 CalAddr = WLANCAL; |
| volatile u16 *calData; |
| |
| /* |
| * Copy the device ID from Flash to device config space. |
| */ |
| |
| calData = (u16 *)CalAddr; |
| |
| #ifndef CONFIG_PCI_CONFIG_DATA_IN_OTP |
| if (calData[0] != 0xa55a && calData[0] != 0x5aa5) |
| { |
| #ifndef COMPRESSED_UBOOT |
| prmsg("BOARD IS NOT CALIBRATED!!!\n"); |
| #endif |
| return; |
| } |
| #else |
| return; |
| #endif |
| /* |
| ** Need to setup the PCI device to access the internal registers |
| */ |
| if ((is_ar7241() || is_ar7242())) |
| ath_pci_write_config(&hose, NULL, 0x10, 0x1000ffff); |
| else |
| ath_pci_write_config(&hose, NULL, 0x10, 0xffff); |
| |
| ath_pci_write_config(&hose, NULL, 0x04, 0x6); |
| |
| #ifdef PCIE2_APP_ADDRESS |
| ath_pci_write_config_rc2(&hose, NULL, 0x10, 0xffff); |
| |
| ath_pci_write_config_rc2(&hose, NULL, 0x04, 0x6); |
| #endif |
| |
| /* |
| ** Set pointer to first reg address |
| */ |
| |
| calData += ATH_ART_PCICFG_OFFSET; |
| |
| while(*calData != 0xffff) |
| { |
| u16 cd; |
| |
| cd = *calData++; |
| addr = BaseAddr + cd; |
| val = *calData++; |
| val |= (*calData++) << 16; |
| |
| ath_reg_wr_nf(addr,val); |
| udelay(100); |
| } |
| |
| return; |
| } |
| |
| |
| /******************************************************************************/ |
| /*! |
| ** \brief pci host initialization |
| ** |
| ** Sets up the PCI controller on the host. For AR7240 this may not be necessary, |
| ** but this function is required for board support. |
| ** |
| ** We want a 1:1 mapping between PCI and DDR for inbound and outbound. |
| ** The PCI<---AHB decoding works as follows: |
| ** |
| ** 8 registers in the DDR unit provide software configurable 32 bit offsets |
| ** for each of the eight 16MB PCI windows in the 128MB. The offsets will be |
| ** added to any address in the 16MB segment before being sent to the PCI unit. |
| ** |
| ** Essentially for any AHB address generated by the CPU, |
| ** 1. the MSB four bits are stripped off, [31:28], |
| ** 2. Bit 27 is used to decide between the lower 128Mb (PCI) or the rest of |
| ** the AHB space |
| ** 3. Bits 26:24 are used to access one of the 8 window registers and are |
| ** masked off. |
| ** 4. If it is a PCI address, then the WINDOW offset in the WINDOW register |
| ** corresponding to the next 3 bits (bit 26:24) is ADDED to the address, |
| ** to generate the address to PCI unit. |
| ** |
| ** eg. CPU address = 0x100000ff |
| ** window 0 offset = 0x10000000 |
| ** This points to lowermost 16MB window in PCI space. |
| ** So the resulting address would be 0x000000ff+0x10000000 |
| ** = 0x100000ff |
| ** |
| ** eg2. CPU address = 0x120000ff |
| ** WINDOW 2 offset = 0x12000000 |
| ** resulting address would be 0x000000ff+0x12000000 |
| ** = 0x120000ff |
| ** |
| ** There is no translation for inbound access (PCI device as a master) |
| ** |
| ** \return N/A |
| */ |
| |
| #ifdef COMPRESSED_UBOOT |
| # define PCI_INIT_RET_TYPE int |
| # define PCI_INIT_RETURN return 0 |
| #else |
| # define PCI_INIT_RET_TYPE void |
| # define PCI_INIT_RETURN return |
| #endif |
| |
| PCI_INIT_RET_TYPE |
| pci_init_board (void) |
| { |
| #ifdef CONFIG_ATH_EMULATION |
| prmsg("--- Skipping %s for emulation\n", __func__); |
| #else |
| uint32_t cmd; |
| |
| if (is_drqfn() && !is_qca953x()) { |
| /* |
| * Dont enable PCIe in DRQFN package as it has some issues |
| * related to PCIe |
| */ |
| PCI_INIT_RETURN; |
| } |
| |
| #if defined(CONFIG_MACH_QCA953x) |
| if (ath_reg_rd(RST_BOOTSTRAP_ADDRESS) & RST_BOOTSTRAP_TESTROM_ENABLE_MASK) { |
| ath_reg_rmw_clear(RST_MISC2_ADDRESS, RST_MISC2_PERSTN_RCPHY_SET(1)); |
| |
| ath_reg_wr(PCIE_PHY_REG_1_ADDRESS, PCIE_PHY_REG_1_RESET_1); |
| ath_reg_wr(PCIE_PHY_REG_3_ADDRESS, PCIE_PHY_REG_3_RESET_1); |
| |
| ath_reg_rmw_set(PCIE_PWR_MGMT_ADDRESS, PCIE_PWR_MGMT_ASSERT_CLKREQN_SET(1)); |
| |
| ath_reg_rmw_set(PCIE_PLL_CONFIG_ADDRESS, PCIE_PLL_CONFIG_PLLPWD_SET(1)); |
| |
| ath_reg_rmw_set(RST_RESET_ADDRESS, RST_RESET_PCIE_RESET_SET(1)); |
| ath_reg_rmw_set(RST_RESET_ADDRESS, RST_RESET_PCIE_PHY_RESET_SET(1)); |
| |
| ath_reg_rmw_clear(RST_CLKGAT_EN_ADDRESS, RST_CLKGAT_EN_PCIE_RC_SET(1)); |
| |
| PCI_INIT_RETURN; |
| } else { |
| /* Honeybee -The PCIe reference clock frequency is being changed |
| to vary from 99.968MHz to 99.999MHz using SS modulation */ |
| ath_reg_wr_nf(PCIE_PLL_DITHER_DIV_MAX_ADDRESS, |
| 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(0x17) | |
| PCIE_PLL_DITHER_DIV_MAX_DIV_MAX_FRAC_SET(0x3fff)); |
| |
| ath_reg_wr_nf(PCIE_PLL_DITHER_DIV_MIN_ADDRESS, |
| PCIE_PLL_DITHER_DIV_MIN_DIV_MIN_FRAC_SET(0x3f84)| |
| PCIE_PLL_DITHER_DIV_MIN_DIV_MIN_INT_SET(0x17)); |
| } |
| #else |
| |
| #if defined(CONFIG_MACH_QCA956x) |
| |
| ath_reg_rmw_set(PCIE_PHY_REG_1_ADDRESS, PCIE_PHY_REG_1_S_SET(PCIE_PHY_REG_1_S_RESET)); |
| |
| ath_reg_wr_nf(PCIE_PLL_DITHER_DIV_MAX_ADDRESS, |
| 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(PCIE_PLL_DITHER_DIV_MIN_ADDRESS, |
| PCIE_PLL_DITHER_DIV_MIN_DIV_MIN_FRAC_SET(0x3f84) | |
| PCIE_PLL_DITHER_DIV_MIN_DIV_MIN_INT_SET(0x17)); |
| #else |
| // common for rc1 and rc2 |
| ath_reg_wr_nf(PCIE_PLL_DITHER_DIV_MAX_ADDRESS, |
| 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(PCIE_PLL_DITHER_DIV_MIN_ADDRESS, |
| PCIE_PLL_DITHER_DIV_MIN_DIV_MIN_INT_SET(0x14)); |
| #endif |
| |
| #endif |
| |
| ath_reg_wr_nf(PCIE_PLL_CONFIG_ADDRESS, |
| PCIE_PLL_CONFIG_REFDIV_SET(1) | |
| PCIE_PLL_CONFIG_BYPASS_SET(1) | |
| PCIE_PLL_CONFIG_PLLPWD_SET(1)); |
| udelay(10000); |
| |
| ath_reg_rmw_clear(PCIE_PLL_CONFIG_ADDRESS, PCIE_PLL_CONFIG_PLLPWD_SET(1)); |
| udelay(1000); |
| ath_reg_rmw_clear(PCIE_PLL_CONFIG_ADDRESS, PCIE_PLL_CONFIG_BYPASS_SET(1)); |
| udelay(1000); |
| |
| #if !defined(CONFIG_MACH_QCA956x) |
| |
| #ifdef PCIE2_APP_ADDRESS |
| if (!(ath_reg_rd(RST_BOOTSTRAP_ADDRESS) & RST_BOOTSTRAP_PCIE_RC_EP_SELECT_MASK)) { |
| pci_rc2_init_board(); |
| return; |
| } |
| #endif |
| |
| ath_reg_rmw_set(RST_RESET_ADDRESS, RST_RESET_PCIE_PHY_RESET_SET(1)); |
| udelay(10000); |
| |
| ath_reg_rmw_set(RST_RESET_ADDRESS, RST_RESET_PCIE_RESET_SET(1)); |
| udelay(10000); |
| |
| #ifdef PCIE2_APP_ADDRESS |
| ath_reg_rmw_clear(RST_MISC2_ADDRESS, RST_MISC2_PERSTN_RCPHY_SET(1)); |
| udelay(10000); |
| #endif |
| |
| ath_reg_wr_nf(PCIE_RESET_ADDRESS, 0); // Put endpoint in reset |
| udelay(100000); |
| |
| #ifdef PCIE2_APP_ADDRESS |
| ath_reg_rmw_set(RST_MISC2_ADDRESS, RST_MISC2_PERSTN_RCPHY_SET(1)); |
| udelay(10000); |
| #endif |
| |
| ath_reg_rmw_clear(RST_RESET_ADDRESS, RST_RESET_PCIE_PHY_RESET_SET(1)); |
| udelay(10000); |
| |
| ath_reg_rmw_clear(RST_RESET_ADDRESS, RST_RESET_PCIE_RESET_SET(1)); |
| udelay(10000); |
| |
| ath_reg_wr_nf(PCIE_APP_ADDRESS, PCIE_APP_PCIE_BAR_MSN_SET(1) | |
| PCIE_APP_CFG_BE_SET(0xf) | |
| PCIE_APP_SLV_RESP_ERR_MAP_SET(0x3f) | |
| PCIE_APP_LTSSM_ENABLE_SET(1)); |
| |
| cmd = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | |
| PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK; |
| |
| ath_local_write_config(PCI_COMMAND, 4, cmd); |
| ath_local_write_config(0x20, 4, 0x1ff01000); |
| ath_local_write_config(0x24, 4, 0x1ff01000); |
| |
| ath_reg_wr_nf(PCIE_RESET_ADDRESS, 4); // Pull endpoint out of reset |
| udelay(100000); |
| |
| /* |
| * Check if the WLAN PCI-E H/W is present, If the |
| * WLAN H/W is not present, skip the PCI platform |
| * initialization code and return |
| */ |
| if (((ath_reg_rd(PCIE_RESET_ADDRESS)) & 0x1) == 0x0) { |
| prmsg("*** Warning *** : PCIe WLAN Module not found !!!\n"); |
| } |
| #endif |
| |
| #ifdef PCIE2_APP_ADDRESS |
| pci_rc2_init_board(); |
| #endif |
| |
| #ifndef COMPRESSED_UBOOT |
| /* |
| * Now, configure for u-boot tools |
| */ |
| |
| hose.first_busno = 0; |
| hose.last_busno = 0xff; |
| |
| /* System space */ |
| pci_set_region( &hose.regions[0], |
| 0x80000000, |
| 0x00000000, |
| 32 * 1024 * 1024, |
| PCI_REGION_MEM | PCI_REGION_MEMORY); |
| |
| /* PCI memory space */ |
| pci_set_region( &hose.regions[1], |
| 0x10000000, |
| 0x10000000, |
| 128 * 1024 * 1024, |
| PCI_REGION_MEM); |
| |
| hose.region_count = 2; |
| |
| pci_register_hose(&hose); |
| |
| pci_set_ops( &hose, |
| pci_hose_read_config_byte_via_dword, |
| pci_hose_read_config_word_via_dword, |
| ath_pci_read_config, |
| pci_hose_write_config_byte_via_dword, |
| pci_hose_write_config_word_via_dword, |
| ath_pci_write_config); |
| #endif |
| plat_dev_init(); |
| #endif /* CONFIG_ATH_EMULATION */ |
| |
| PCI_INIT_RETURN; |
| } |
| |
| #ifdef PCIE2_APP_ADDRESS |
| void |
| pci_rc2_init_board (void) |
| { |
| #if defined(CONFIG_MACH_QCA956x) |
| ath_reg_rmw_clear(GPIO_OE_ADDRESS, 0x1); |
| udelay(10000); |
| ath_reg_rmw_set(GPIO_OUT_FUNCTION0_ADDRESS, GPIO_OUT_FUNCTION0_ENABLE_GPIO_0_SET(0x73)); |
| udelay(10000); |
| ath_reg_rmw_set(RST_RESET_ADDRESS,RST_RESET_PCIE_PHY_RESET_SET(1) | |
| RST_RESET_PCIE_RESET_SET(1)); |
| |
| udelay(10000); |
| ath_reg_rmw_clear(RST_RESET_ADDRESS,RST_RESET_PCIE_PHY_RESET_SET(1) | |
| RST_RESET_PCIE_RESET_SET(1)); |
| |
| udelay(10000); |
| ath_reg_rmw_set(RST_RESET2_ADDRESS,RST_RESET_PCIE_PHY_RESET_SET(1) | |
| RST_RESET_PCIE_RESET_SET(1)); |
| |
| udelay(10000); |
| ath_reg_rmw_clear(RST_RESET2_ADDRESS,RST_RESET_PCIE_PHY_RESET_SET(1) | |
| RST_RESET_PCIE_RESET_SET(1)); |
| |
| udelay(10000); |
| ath_reg_wr(PCIE2_RESET_ADDRESS,PCIE2_RESET_EP_RESET_L_SET(1)); |
| udelay(10000); |
| ath_reg_wr(ATH_PCI_CRP_WRDATA,0x6); |
| udelay(10000); |
| ath_reg_wr(PCIE_APP_ADDRESS,PCIE_APP_LTSSM_ENABLE_SET(1) | |
| PCIE_APP_SLV_RESP_ERR_MAP_SET(0x3f) | |
| PCIE_APP_CFG_BE_SET(0xf) | |
| PCIE_APP_PCIE_BAR_MSN_SET(1)); |
| udelay(10000); |
| ath_reg_wr(PCIE_INT_MASK_ADDRESS,PCIE_INT_MASK_CORR_ERR_SET(1) | |
| PCIE_INT_MASK_NONFATAL_ERR_SET(1) | |
| PCIE_INT_MASK_FATAL_ERR_SET(1) | |
| PCIE_INT_MASK_GM_COMP_LOOKUP_ERR_SET(1) | |
| PCIE_INT_MASK_RADMX_COMP_LOOKUP_ERR_SET(1) | |
| PCIE_INT_MASK_INTA_SET(1) | |
| PCIE_INT_MASK_INTB_SET(1) | |
| PCIE_INT_MASK_INTC_SET(1) | |
| PCIE_INT_MASK_INTD_SET(1) | |
| PCIE_INT_MASK_MSI_SET(1) | |
| PCIE_INT_MASK_MSI_ERR_SET(1) | |
| PCIE_INT_MASK_AER_INT_SET(1) | |
| PCIE_INT_MASK_AER_MSI_SET(1) | |
| PCIE_INT_MASK_SYS_ERR_SET(1) | |
| PCIE_INT_MASK_INTAL_SET(1) | |
| PCIE_INT_MASK_INTBL_SET(1) | |
| PCIE_INT_MASK_INTCL_SET(1) | |
| PCIE_INT_MASK_INTDL_SET(1)); |
| udelay(10000); |
| ath_local_write_config_rc2(0x70c, 4, 0x1b403200); |
| udelay(10000); |
| ath_reg_wr(PCIE_DEBUG_ADDRESS,PCIE_DEBUG_BYTESWAP_SET(1)); |
| udelay(10000); |
| |
| ath_reg_rmw_set(XTAL2_SEC_ADDRESS, XTAL2_SEC_SPARE_SET(0xc)); |
| udelay(10000); |
| ath_reg_rmw_clear(PCIe_DPLL2_ADDRESS, PCIe_DPLL2_KI_SET(0x3) | |
| PCIe_DPLL2_KD_SET(0xF)); |
| udelay(10000); |
| ath_reg_rmw_set(PCIe_DPLL2_ADDRESS, PCIe_DPLL2_KD_SET(0x4)); |
| udelay(10000); |
| |
| #else |
| |
| uint32_t cmd; |
| |
| ath_reg_rmw_set(RST_RESET2_ADDRESS, RST_RESET2_PCIE2_PHY_RESET_SET(1)); |
| udelay(10000); |
| |
| ath_reg_rmw_set(RST_RESET2_ADDRESS, RST_RESET2_PCIE2_RESET_SET(1)); |
| udelay(10000); |
| |
| ath_reg_rmw_clear(RST_MISC2_ADDRESS, RST_MISC2_PERSTN_RCPHY2_SET(1)); |
| udelay(10000); |
| |
| ath_reg_wr_nf(PCIE2_RESET_ADDRESS, 0); // Put endpoint in reset |
| udelay(100000); |
| |
| ath_reg_rmw_set(RST_MISC2_ADDRESS, RST_MISC2_PERSTN_RCPHY2_SET(1)); |
| udelay(10000); |
| |
| ath_reg_rmw_clear(RST_RESET2_ADDRESS, RST_RESET_PCIE_PHY_RESET_SET(1)); |
| udelay(10000); |
| |
| ath_reg_rmw_clear(RST_RESET2_ADDRESS, RST_RESET_PCIE_RESET_SET(1)); |
| udelay(10000); |
| |
| ath_reg_wr_nf(PCIE2_APP_ADDRESS, PCIE2_APP_PCIE2_BAR_MSN_SET(1) | |
| PCIE2_APP_CFG_BE_SET(0xf) | |
| PCIE2_APP_SLV_RESP_ERR_MAP_SET(0x3f) | |
| PCIE2_APP_LTSSM_ENABLE_SET(1)); |
| |
| cmd = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | |
| PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK; |
| |
| ath_local_write_config_rc2(PCI_COMMAND, 4, cmd); |
| ath_local_write_config_rc2(0x20, 4, 0x1ff01000); |
| ath_local_write_config_rc2(0x24, 4, 0x1ff01000); |
| |
| ath_reg_wr_nf(PCIE2_RESET_ADDRESS, 4); // Pull endpoint out of reset |
| udelay(100000); |
| |
| #endif |
| /* |
| * Check if the WLAN PCI-E H/W is present, If the |
| * WLAN H/W is not present, skip the PCI platform |
| * initialization code and return |
| */ |
| if (((ath_reg_rd(PCIE2_RESET_ADDRESS)) & 0x1) == 0x0) { |
| prmsg("*** Warning *** : PCIe WLAN Module not found !!!\n"); |
| return; |
| } |
| } |
| #endif |