| /* |
| * 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 "ar7240_soc.h" |
| |
| /* |
| ** PCI controller "hose" value |
| */ |
| |
| static struct pci_controller hose; |
| |
| static int ar7240_local_read_config(int where, int size, uint32_t *value); |
| static int ar7240_local_write_config(int where, int size, uint32_t value); |
| |
| static int |
| ar7240_local_read_config(int where, int size, uint32_t *value) |
| { |
| *value = ar7240_reg_rd(AR7240_PCI_CRP + where); |
| return 0; |
| } |
| |
| static int |
| ar7240_local_write_config(int where, int size, uint32_t value) |
| { |
| ar7240_reg_wr((AR7240_PCI_CRP + where),value); |
| return 0; |
| } |
| |
| static int |
| ar7240_pci_read_config(struct pci_controller *hose, |
| pci_dev_t dev, int where, uint32_t *value) |
| { |
| *value = ar7240_reg_rd(AR7240_PCI_DEV_CFGBASE + where); |
| return 0; |
| } |
| |
| static int |
| ar7240_pci_write_config(struct pci_controller *hose, |
| pci_dev_t dev, int where, uint32_t value) |
| { |
| ar7240_reg_wr((AR7240_PCI_DEV_CFGBASE + where),value); |
| return 0; |
| } |
| |
| /* |
| ** 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 ) |
| { |
| /* |
| ** Board is not calibrated. |
| */ |
| #ifndef COMPRESSED_UBOOT |
| printf("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())) |
| ar7240_pci_write_config(&hose, NULL, 0x10, 0x1000ffff); |
| else |
| ar7240_pci_write_config(&hose, NULL, 0x10, 0xffff); |
| |
| ar7240_pci_write_config(&hose, NULL, 0x04, 0x6); |
| |
| /* |
| ** Set pointer to first reg address |
| */ |
| |
| calData += AR7240_ART_PCICFG_OFFSET; |
| |
| while(*calData != 0xffff) |
| { |
| u16 cd; |
| |
| cd = *calData++; |
| addr = BaseAddr + cd; |
| val = *calData++; |
| val |= (*calData++) << 16; |
| |
| ar7240_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 CONFIG_WASP_SUPPORT |
| static int ar7240_pcibios_init(void) |
| { |
| if (is_ar9341()) { |
| return 0; |
| } |
| |
| if (((ar7240_reg_rd(AR7240_PCI_LCL_RESET)) & 0x1) == 0x0) { |
| printf("***** Warning *****: PCIe WLAN H/W not found !!!\n"); |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| #define pci_udelay(n) do { uint32_t i; /* printf("--- %s[%d] udelay(%u)\n", __func__, __LINE__, n); */ for (i = 0; i < ((n)/10); i++) udelay(10); } while (0) |
| |
| char * |
| __print_llx(unsigned long long u, char *num) |
| { |
| char dec[] = "0123456789"; |
| int i; |
| |
| if (u == 0) return "0"; |
| |
| memset(num, 0, 32); |
| |
| for (i = 24; u; i--) { |
| num[i] = dec[u % 10]; |
| u = u / 10; |
| } |
| |
| return &num[i+1]; |
| } |
| |
| #define print_llx(n) __print_llx(n, str_##n) |
| |
| #ifdef COMPRESSED_UBOOT |
| int pci_init_board (void) |
| #else |
| void pci_init_board (void) |
| #endif /* #ifdef COMPRESSED_UBOOT */ |
| { |
| #ifdef CONFIG_AP123 |
| return; |
| #else |
| uint32_t cmd = 0, reg_val; |
| |
| |
| //printf("%s: PCIe PLL 0x%x\n", __func__, mips3_cp0_count_read()); |
| //printf("%s: PCIe PLL 0x%x 0xb8000008 = 0x%08x\n", __func__, mips3_cp0_count_read(), ar7240_reg_rd(0xb8040008)); |
| |
| pci_udelay(100000); |
| //count ++; |
| |
| if ((ar7240_reg_rd(WASP_BOOTSTRAP_REG) & WASP_REF_CLK_25) == 0) { |
| ar7240_reg_wr_nf(AR934X_PCIE_PLL_DITHER_DIV_MAX, |
| PCIE_PLL_DITHER_DIV_MAX_EN_DITHER_SET(0) | |
| PCIE_PLL_DITHER_DIV_MAX_USE_MAX_SET(1) | |
| PCIE_PLL_DITHER_DIV_MAX_DIV_MAX_INT_SET(0x20) | |
| PCIE_PLL_DITHER_DIV_MAX_DIV_MAX_FRAC_SET(0)); |
| } else { |
| #ifndef COMPRESSED_UBOOT |
| printf("%s: PCIe PLL not set for 40MHz refclk\n", __func__); |
| #endif |
| } |
| |
| ar7240_reg_rmw_set(AR7240_RESET, AR7240_RESET_PCIE); // core in reset |
| pci_udelay(10000); |
| ar7240_reg_rmw_set(AR7240_RESET, AR7240_RESET_PCIE_PHY);// phy in reset |
| pci_udelay(10000); |
| ar7240_reg_rmw_clear(RST_MISC2_ADDRESS, RST_MISC2_PERSTN_RCPHY_SET(1)); // pci phy analog in reset |
| pci_udelay(10000); |
| ar7240_reg_wr(0x180f0000, 0x1ffc0); // ltssm is disabled |
| pci_udelay(100); |
| ar7240_reg_wr_nf(AR7240_PCI_LCL_RESET, 0); // End point in reset |
| pci_udelay(100000); |
| |
| |
| //ar7240_reg_rmw_clear(AR7240_RESET, AR7240_RESET_PCIE_PHY); |
| |
| if ((ar7240_reg_rd(AR7240_REV_ID) & 0xf) == 0) { |
| ar7240_reg_wr_nf(AR934X_PCIE_PLL_CONFIG, |
| PCIE_PLL_CONFIG_REFDIV_SET(1) | |
| PCIE_PLL_CONFIG_BYPASS_SET(1) | |
| PCIE_PLL_CONFIG_PLLPWD_SET(1)); |
| pci_udelay(10000); |
| ar7240_reg_wr_nf(AR934X_PCIE_PLL_CONFIG, |
| PCIE_PLL_CONFIG_REFDIV_SET(1) | |
| PCIE_PLL_CONFIG_BYPASS_SET(1) | |
| PCIE_PLL_CONFIG_PLLPWD_SET(0)); |
| pci_udelay(1000); |
| ar7240_reg_wr_nf(AR934X_PCIE_PLL_CONFIG, |
| ar7240_reg_rd(AR934X_PCIE_PLL_CONFIG) & |
| (~PCIE_PLL_CONFIG_BYPASS_SET(1))); |
| pci_udelay(1000); |
| } else { |
| ar7240_reg_wr_nf(AR934X_PCIE_PLL_CONFIG, |
| PCIE_PLL_CONFIG_REFDIV_SET(2) | |
| PCIE_PLL_CONFIG_BYPASS_SET(1) | |
| PCIE_PLL_CONFIG_PLLPWD_SET(1)); |
| pci_udelay(10000); |
| |
| if ((ar7240_reg_rd(WASP_BOOTSTRAP_REG) & WASP_REF_CLK_25) == 0) { |
| ar7240_reg_wr_nf(0xb8116c00, (0x5 << 27) | (160 << 18) | 0); |
| } else { |
| ar7240_reg_wr_nf(0xb8116c00, (0x2 << 27) | (0x28 << 18) | 0); |
| } |
| do { |
| ar7240_reg_wr_nf(0xb8116c04, (0x1 << 30) | (0x4 << 26) | (0x32 << 19) | (1 << 16) | (3 << 13) | (0x1e << 7)); |
| ar7240_reg_wr_nf(0xb8116c08, (6 << 23)); |
| pci_udelay(10000); |
| ar7240_reg_wr_nf(0xb8116c04, (0x1 << 30) | (0x4 << 26) | (0x32 << 19) | (3 << 13) | (0x1e << 7)); |
| |
| ar7240_reg_rmw_clear(KSEG1ADDR(PCIe_DPLL3_ADDRESS), PCIe_DPLL3_DO_MEAS_SET(1)); |
| ar7240_reg_rmw_set(KSEG1ADDR(PCIe_DPLL3_ADDRESS), PCIe_DPLL3_DO_MEAS_SET(1)); |
| |
| ar7240_reg_wr(0xb804000c, 1 << 2); |
| |
| pci_udelay(1000); |
| |
| while (((cmd = ar7240_reg_rd(PCIe_DPLL4_ADDRESS)) & PCIe_DPLL4_MEAS_DONE_SET(1)) == 0) { |
| printf("0x%x 0x%x 0x%x\n", KSEG1ADDR(PCIe_DPLL4_ADDRESS), cmd); |
| pci_udelay(10); |
| } |
| |
| { int i; for (i = 0; i < 100; i++) udelay(10); } |
| #if 0 |
| msdvc = PCIe_DPLL4_MEAN_DVC_GET(cmd); |
| cmd = PCIe_DPLL3_SQSUM_DVC_GET(ar7240_reg_rd(PCIe_DPLL3_ADDRESS)); |
| |
| if (msdvc & 0x400) msdvc = ((~msdvc & 0x7FF) + 1); /* 11 bit signed number , but not intentioanlly multiply by (-1), ASK VIPUL*/ |
| msdvc = cmd - (msdvc *msdvc); |
| msdvc_sq = msdvc * msdvc; |
| |
| if (cmd >= 0x40000) { |
| err_count++; |
| if (sqsum_min_fail == 0) |
| sqsum_min_fail = cmd; |
| if (cmd > sqsum_max_fail) |
| sqsum_max_fail = cmd; |
| if (cmd < sqsum_min_fail) |
| sqsum_min_fail = cmd; |
| sqsum_avg_fail = (sqsum_avg_fail - (sqsum_avg_fail / err_count)) + (cmd / err_count); |
| |
| if (num_pll_loops == 0) |
| err_pll1++; |
| if (num_pll_loops == 1) |
| err_pll2++; |
| if (num_pll_loops == 2) |
| err_pll3++; |
| if (num_pll_loops == 3) |
| err_pll4++; |
| if (num_pll_loops == 4) { |
| err_pll5++; |
| break; |
| } |
| } else { |
| if (sqsum_min == 0) |
| sqsum_min = cmd; |
| if (cmd < sqsum_min) |
| sqsum_min = cmd; |
| if (cmd > sqsum_max) |
| sqsum_max = cmd; |
| //sqsum_avg = (sqsum_avg - (sqsum_avg / count)) + (cmd / count); |
| sqsum_avg += cmd; |
| |
| /*msdvc calc*/ |
| if (msdvc_min == 0) msdvc_min = msdvc; |
| if (msdvc < msdvc_min) msdvc_min =msdvc; |
| if (msdvc > msdvc_max) msdvc_max =msdvc; |
| msdvc_avg += msdvc; |
| msdvc_sq_avg += msdvc_sq; |
| |
| } |
| num_pll_loops++; |
| #endif |
| |
| } while ((cmd = PCIe_DPLL3_SQSUM_DVC_GET(ar7240_reg_rd(PCIe_DPLL3_ADDRESS))) >= 0x40000); |
| |
| ar7240_reg_rmw_clear(AR934X_PCIE_PLL_CONFIG, PCIE_PLL_CONFIG_PLLPWD_SET(1)); |
| pci_udelay(10000); |
| ar7240_reg_rmw_clear(AR934X_PCIE_PLL_CONFIG, PCIE_PLL_CONFIG_BYPASS_SET(1)); |
| pci_udelay(10000); |
| |
| /* |
| * PCIe Dithering configuration |
| */ |
| if (is_ar934x_12_or_later()) { |
| ar7240_reg_wr_nf(PCIe_DPLL2_ADDRESS, |
| PCIe_DPLL2_LOCAL_PLL_SET(0) | |
| PCIe_DPLL2_KI_SET(0x4)| |
| PCIe_DPLL2_KD_SET(0x40)); |
| ar7240_reg_wr_nf(AR934X_PCIE_PLL_CONFIG, 0x40010800); |
| ar7240_reg_wr_nf(AR934X_PCIE_PLL_DITHER_DIV_MAX, 0xc013fffe); |
| ar7240_reg_wr_nf(AR934X_PCIE_PLL_DITHER_DIV_MIN, 0x0013e666); |
| |
| ar7240_reg_wr_nf(AR934X_PCIE_PLL_CONFIG, 0x00010800); |
| ar7240_reg_wr_nf(AR934X_PCIE_PLL_CONFIG, 0x00000800); |
| } |
| |
| //run_command("md 0xb8116c00 4", 0); |
| } |
| ar7240_reg_rmw_set(RST_MISC2_ADDRESS, RST_MISC2_PERSTN_RCPHY_SET(1)); // pci phy analog out of reset |
| pci_udelay(10000); |
| |
| ar7240_reg_rmw_clear(AR7240_RESET, AR7240_RESET_PCIE_PHY); // phy out of reset |
| pci_udelay(10000); |
| |
| ar7240_reg_rmw_clear(AR7240_RESET, AR7240_RESET_PCIE); // core out of reset |
| pci_udelay(1000); |
| |
| cmd = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | |
| PCI_COMMAND_PARITY|PCI_COMMAND_SERR|PCI_COMMAND_FAST_BACK; |
| |
| ar7240_local_write_config(PCI_COMMAND, 4, cmd); // pci cmd reg init |
| ar7240_local_write_config(0x20, 4, 0x1ff01000); // membase setting |
| ar7240_local_write_config(0x24, 4, 0x1ff01000); // prefetch membase setting |
| |
| |
| if ((is_ar7241() || is_ar7242() || is_wasp())) { |
| ar7240_reg_wr(0x180f0000, 0x1ffc1); // ltssm enable |
| } else { |
| ar7240_reg_wr(0x180f0000, 0x1); |
| } |
| pci_udelay(100000); |
| |
| ar7240_reg_wr_nf(AR7240_PCI_LCL_RESET, 4); // EP out of reset |
| pci_udelay(100000); |
| |
| |
| #ifdef COMPRESSED_UBOOT |
| pci_udelay(100); |
| #else |
| /* |
| * Delay increased from 100 to 1000, so as to |
| * get the correct status from PCI LCL RESET register |
| */ |
| pci_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 (((ar7240_reg_rd(AR7240_PCI_LCL_RESET)) & 0x1) == 0x0) { |
| printf("*** Warning *** : PCIe WLAN Module not found !!!\n"); |
| return; |
| } |
| #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, |
| ar7240_pci_read_config, |
| pci_hose_write_config_byte_via_dword, |
| pci_hose_write_config_word_via_dword, |
| ar7240_pci_write_config); |
| #endif |
| plat_dev_init(); |
| #endif // CONFIG_AP123 |
| #ifdef COMPRESSED_UBOOT |
| return 0; |
| #endif |
| } |
| #else |
| // For non - wasp |
| #ifdef COMPRESSED_UBOOT |
| int pci_init_board (void) |
| #else |
| void pci_init_board (void) |
| #endif /* #ifdef COMPRESSED_UBOOT */ |
| { |
| uint32_t cmd; |
| |
| |
| ar7240_reg_rmw_clear(AR7240_RESET,AR7240_RESET_PCIE_PHY_SERIAL); |
| udelay(100); |
| |
| ar7240_reg_rmw_clear(AR7240_RESET, AR7240_RESET_PCIE_PHY); |
| |
| |
| ar7240_reg_rmw_clear(AR7240_RESET, AR7240_RESET_PCIE); |
| |
| ar7240_reg_wr_nf(AR7240_PCI_LCL_RESET, 0); |
| udelay(100000); |
| |
| /* |
| * Initialize PCIE PLL and get it out of RESET |
| */ |
| ar7240_reg_wr(AR7240_PCIE_PLL_CONFIG,0x02050800); |
| |
| ar7240_reg_wr(AR7240_PCIE_PLL_CONFIG,0x00050800); |
| udelay(100); |
| |
| ar7240_reg_wr(AR7240_PCIE_PLL_CONFIG,0x00040800); |
| udelay(100000); |
| |
| ar7240_reg_wr_nf(AR7240_PCI_LCL_RESET, 4); |
| udelay(100000); |
| |
| cmd = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | |
| PCI_COMMAND_PARITY|PCI_COMMAND_SERR|PCI_COMMAND_FAST_BACK; |
| |
| ar7240_local_write_config(PCI_COMMAND, 4, cmd); |
| ar7240_local_write_config(0x20, 4, 0x1ff01000); |
| ar7240_local_write_config(0x24, 4, 0x1ff01000); |
| |
| if ((is_ar7241() || is_ar7242() || is_wasp())) { |
| ar7240_reg_wr(0x180f0000, 0x1ffc1); |
| } else { |
| ar7240_reg_wr(0x180f0000, 0x1); |
| } |
| |
| #ifdef COMPRESSED_UBOOT |
| udelay(100); |
| #else |
| udelay(1000); |
| |
| /* |
| * 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 (((ar7240_reg_rd(AR7240_PCI_LCL_RESET)) & 0x1) == 0x0) { |
| printf("*** Warning *** : PCIe WLAN Module not found !!!\n"); |
| return; |
| } |
| #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, |
| ar7240_pci_read_config, |
| pci_hose_write_config_byte_via_dword, |
| pci_hose_write_config_word_via_dword, |
| ar7240_pci_write_config); |
| #endif |
| plat_dev_init(); |
| #ifdef COMPRESSED_UBOOT |
| return 0; |
| #endif |
| } |
| #endif /* CONFIG_WASP_SUPPORT */ |