blob: 332f0427ab91830ff33043ea33233a57b38b6bbf [file] [log] [blame]
/*
* 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 */