diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-09 18:10:34 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-09 18:10:34 -0700 |
commit | 82abb273d838318424644d8f02825db0fbbd400a (patch) | |
tree | e1ea8a92db4ba68f347249986ffe3a25ffbf8219 /arch/mips/netlogic | |
parent | 9b651cc2277b5e4883012ebab0fea2bcda4cbafa (diff) | |
parent | f8647b506d7116a1a3accd8d618184096e85f50b (diff) |
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS updates from Ralf Baechle:
- three fixes for 3.15 that didn't make it in time
- limited Octeon 3 support.
- paravirtualization support
- improvment to platform support for Netlogix SOCs.
- add support for powering down the Malta eval board in software
- add many instructions to the in-kernel microassembler.
- add support for the BPF JIT.
- minor cleanups of the BCM47xx code.
- large cleanup of math emu code resulting in significant code size
reduction, better readability of the code and more accurate
emulation.
- improvments to the MIPS CPS code.
- support C3 power status for the R4k count/compare clock device.
- improvments to the GIO support for older SGI workstations.
- increase number of supported CPUs to 256; this can be reached on
certain embedded multithreaded ccNUMA configurations.
- various small cleanups, updates and fixes
* 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (173 commits)
MIPS: IP22/IP28: Improve GIO support
MIPS: Octeon: Add twsi interrupt initialization for OCTEON 3XXX, 5XXX, 63XX
DEC: Document the R4k MB ASIC mini interrupt controller
DEC: Add self as the maintainer
MIPS: Add microMIPS MSA support.
MIPS: Replace calls to obsolete strict_strto call with kstrto* equivalents.
MIPS: Replace obsolete strict_strto call with kstrto
MIPS: BFP: Simplify code slightly.
MIPS: Call find_vma with the mmap_sem held
MIPS: Fix 'write_msa_##' inline macro.
MIPS: Fix MSA toolchain support detection.
mips: Update the email address of Geert Uytterhoeven
MIPS: Add minimal defconfig for mips_paravirt
MIPS: Enable build for new system 'paravirt'
MIPS: paravirt: Add pci controller for virtio
MIPS: Add code for new system 'paravirt'
MIPS: Add functions for hypervisor call
MIPS: OCTEON: Add OCTEON3 to __get_cpu_type
MIPS: Add function get_ebase_cpunum
MIPS: Add minimal support for OCTEON3 to c-r4k.c
...
Diffstat (limited to 'arch/mips/netlogic')
-rw-r--r-- | arch/mips/netlogic/common/irq.c | 2 | ||||
-rw-r--r-- | arch/mips/netlogic/common/reset.S | 39 | ||||
-rw-r--r-- | arch/mips/netlogic/common/smp.c | 12 | ||||
-rw-r--r-- | arch/mips/netlogic/common/smpboot.S | 12 | ||||
-rw-r--r-- | arch/mips/netlogic/common/time.c | 5 | ||||
-rw-r--r-- | arch/mips/netlogic/dts/xlp_gvp.dts | 5 | ||||
-rw-r--r-- | arch/mips/netlogic/xlp/Makefile | 2 | ||||
-rw-r--r-- | arch/mips/netlogic/xlp/ahci-init-xlp2.c | 377 | ||||
-rw-r--r-- | arch/mips/netlogic/xlp/ahci-init.c | 209 | ||||
-rw-r--r-- | arch/mips/netlogic/xlp/dt.c | 3 | ||||
-rw-r--r-- | arch/mips/netlogic/xlp/nlm_hal.c | 283 | ||||
-rw-r--r-- | arch/mips/netlogic/xlp/setup.c | 3 | ||||
-rw-r--r-- | arch/mips/netlogic/xlp/wakeup.c | 16 |
13 files changed, 857 insertions, 111 deletions
diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c index 5afc4b7fce0f..c100b9afa0ab 100644 --- a/arch/mips/netlogic/common/irq.c +++ b/arch/mips/netlogic/common/irq.c @@ -203,6 +203,8 @@ void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *)) xirq = nlm_irq_to_xirq(node, irq); pic_data = irq_get_handler_data(xirq); + if (WARN_ON(!pic_data)) + return; pic_data->extra_ack = xack; } diff --git a/arch/mips/netlogic/common/reset.S b/arch/mips/netlogic/common/reset.S index b231fe1e7a09..701c4bcb9e47 100644 --- a/arch/mips/netlogic/common/reset.S +++ b/arch/mips/netlogic/common/reset.S @@ -35,6 +35,7 @@ #include <asm/asm.h> #include <asm/asm-offsets.h> +#include <asm/cpu.h> #include <asm/cacheops.h> #include <asm/regdef.h> #include <asm/mipsregs.h> @@ -74,13 +75,25 @@ .endm /* + * Allow access to physical mem >64G by enabling ELPA in PAGEGRAIN + * register. This is needed before going to C code since the SP can + * in this region. Called from all HW threads. + */ +.macro xlp_early_mmu_init + mfc0 t0, CP0_PAGEMASK, 1 + li t1, (1 << 29) /* ELPA bit */ + or t0, t1 + mtc0 t0, CP0_PAGEMASK, 1 +.endm + +/* * L1D cache has to be flushed before enabling threads in XLP. * On XLP8xx/XLP3xx, we do a low level flush using processor control * registers. On XLPII CPUs, usual cache instructions work. */ .macro xlp_flush_l1_dcache mfc0 t0, CP0_EBASE, 0 - andi t0, t0, 0xff00 + andi t0, t0, PRID_IMP_MASK slt t1, t0, 0x1200 beqz t1, 15f nop @@ -159,11 +172,15 @@ FEXPORT(nlm_reset_entry) 1: /* Entry point on core wakeup */ mfc0 t0, CP0_EBASE, 0 /* processor ID */ - andi t0, 0xff00 + andi t0, PRID_IMP_MASK li t1, 0x1500 /* XLP 9xx */ beq t0, t1, 2f /* does not need to set coherent */ nop + li t1, 0x1300 /* XLP 5xx */ + beq t0, t1, 2f /* does not need to set coherent */ + nop + /* set bit in SYS coherent register for the core */ mfc0 t0, CP0_EBASE, 1 mfc0 t1, CP0_EBASE, 1 @@ -197,6 +214,9 @@ FEXPORT(nlm_reset_entry) EXPORT(nlm_boot_siblings) /* core L1D flush before enable threads */ xlp_flush_l1_dcache + /* save ra and sp, will be used later (only for boot cpu) */ + dmtc0 ra, $22, 6 + dmtc0 sp, $22, 7 /* Enable hw threads by writing to MAP_THREADMODE of the core */ li t0, CKSEG1ADDR(RESET_DATA_PHYS) lw t1, BOOT_THREAD_MODE(t0) /* t1 <- thread mode */ @@ -225,6 +245,8 @@ EXPORT(nlm_boot_siblings) #endif mtc0 t1, CP0_STATUS + xlp_early_mmu_init + /* mark CPU ready */ li t3, CKSEG1ADDR(RESET_DATA_PHYS) ADDIU t1, t3, BOOT_CPU_READY @@ -238,14 +260,12 @@ EXPORT(nlm_boot_siblings) nop /* - * For the boot CPU, we have to restore registers and - * return + * For the boot CPU, we have to restore ra and sp and return, rest + * of the registers will be restored by the caller */ -4: dmfc0 t0, $4, 2 /* restore SP from UserLocal */ - li t1, 0xfadebeef - dmtc0 t1, $4, 2 /* restore SP from UserLocal */ - PTR_SUBU sp, t0, PT_SIZE - RESTORE_ALL +4: + dmfc0 ra, $22, 6 + dmfc0 sp, $22, 7 jr ra nop EXPORT(nlm_reset_entry_end) @@ -253,6 +273,7 @@ EXPORT(nlm_reset_entry_end) LEAF(nlm_init_boot_cpu) #ifdef CONFIG_CPU_XLP xlp_config_lsu + xlp_early_mmu_init #endif jr ra nop diff --git a/arch/mips/netlogic/common/smp.c b/arch/mips/netlogic/common/smp.c index 6baae15cc7b1..4fde7ac76cc9 100644 --- a/arch/mips/netlogic/common/smp.c +++ b/arch/mips/netlogic/common/smp.c @@ -135,10 +135,6 @@ void nlm_smp_finish(void) local_irq_enable(); } -void nlm_cpus_done(void) -{ -} - /* * Boot all other cpus in the system, initialize them, and bring them into * the boot function @@ -198,7 +194,7 @@ void __init nlm_smp_setup(void) cpumask_scnprintf(buf, ARRAY_SIZE(buf), cpu_possible_mask); pr_info("Possible CPU mask: %s\n", buf); - /* check with the cores we have worken up */ + /* check with the cores we have woken up */ for (ncore = 0, i = 0; i < NLM_NR_NODES; i++) ncore += hweight32(nlm_get_node(i)->coremask); @@ -213,6 +209,7 @@ static int nlm_parse_cpumask(cpumask_t *wakeup_mask) { uint32_t core0_thr_mask, core_thr_mask; int threadmode, i, j; + char buf[64]; core0_thr_mask = 0; for (i = 0; i < NLM_THREADS_PER_CORE; i++) @@ -247,8 +244,8 @@ static int nlm_parse_cpumask(cpumask_t *wakeup_mask) return threadmode; unsupp: - panic("Unsupported CPU mask %lx", - (unsigned long)cpumask_bits(wakeup_mask)[0]); + cpumask_scnprintf(buf, ARRAY_SIZE(buf), wakeup_mask); + panic("Unsupported CPU mask %s", buf); return 0; } @@ -277,7 +274,6 @@ struct plat_smp_ops nlm_smp_ops = { .send_ipi_mask = nlm_send_ipi_mask, .init_secondary = nlm_init_secondary, .smp_finish = nlm_smp_finish, - .cpus_done = nlm_cpus_done, .boot_secondary = nlm_boot_secondary, .smp_setup = nlm_smp_setup, .prepare_cpus = nlm_prepare_cpus, diff --git a/arch/mips/netlogic/common/smpboot.S b/arch/mips/netlogic/common/smpboot.S index 8597657c27fc..805355b0bd05 100644 --- a/arch/mips/netlogic/common/smpboot.S +++ b/arch/mips/netlogic/common/smpboot.S @@ -54,8 +54,9 @@ .set noat .set arch=xlr /* for mfcr/mtcr, XLR is sufficient */ -FEXPORT(xlp_boot_core0_siblings) /* "Master" cpu starts from here */ - dmtc0 sp, $4, 2 /* SP saved in UserLocal */ +/* Called by the boot cpu to wake up its sibling threads */ +NESTED(xlp_boot_core0_siblings, PT_SIZE, sp) + /* CPU register contents lost when enabling threads, save them first */ SAVE_ALL sync /* find the location to which nlm_boot_siblings was relocated */ @@ -65,9 +66,12 @@ FEXPORT(xlp_boot_core0_siblings) /* "Master" cpu starts from here */ dsubu t2, t1 daddu t2, t0 /* call it */ - jr t2 + jalr t2 nop - /* not reached */ + RESTORE_ALL + jr ra + nop +END(xlp_boot_core0_siblings) NESTED(nlm_boot_secondary_cpus, 16, sp) /* Initialize CP0 Status */ diff --git a/arch/mips/netlogic/common/time.c b/arch/mips/netlogic/common/time.c index 13391b8a6031..0c0a1a606f73 100644 --- a/arch/mips/netlogic/common/time.c +++ b/arch/mips/netlogic/common/time.c @@ -82,6 +82,7 @@ static struct clocksource csrc_pic = { static void nlm_init_pic_timer(void) { uint64_t picbase = nlm_get_node(0)->picbase; + u32 picfreq; nlm_pic_set_timer(picbase, PIC_CLOCK_TIMER, ~0ULL, 0, 0); if (current_cpu_data.cputype == CPU_XLR) { @@ -92,7 +93,9 @@ static void nlm_init_pic_timer(void) csrc_pic.read = nlm_get_pic_timer; } csrc_pic.rating = 1000; - clocksource_register_hz(&csrc_pic, pic_timer_freq()); + picfreq = pic_timer_freq(); + clocksource_register_hz(&csrc_pic, picfreq); + pr_info("PIC clock source added, frequency %d\n", picfreq); } void __init plat_time_init(void) diff --git a/arch/mips/netlogic/dts/xlp_gvp.dts b/arch/mips/netlogic/dts/xlp_gvp.dts index 047d27f54487..bb4ecd1d47fc 100644 --- a/arch/mips/netlogic/dts/xlp_gvp.dts +++ b/arch/mips/netlogic/dts/xlp_gvp.dts @@ -26,11 +26,12 @@ interrupt-parent = <&pic>; interrupts = <17>; }; - pic: pic@4000 { - interrupt-controller; + pic: pic@110000 { + compatible = "netlogic,xlp-pic"; #address-cells = <0>; #interrupt-cells = <1>; reg = <0 0x110000 0x200>; + interrupt-controller; }; nor_flash@1,0 { diff --git a/arch/mips/netlogic/xlp/Makefile b/arch/mips/netlogic/xlp/Makefile index ed9a93c04650..be358a8050c5 100644 --- a/arch/mips/netlogic/xlp/Makefile +++ b/arch/mips/netlogic/xlp/Makefile @@ -2,3 +2,5 @@ obj-y += setup.o nlm_hal.o cop2-ex.o dt.o obj-$(CONFIG_SMP) += wakeup.o obj-$(CONFIG_USB) += usb-init.o obj-$(CONFIG_USB) += usb-init-xlp2.o +obj-$(CONFIG_SATA_AHCI) += ahci-init.o +obj-$(CONFIG_SATA_AHCI) += ahci-init-xlp2.o diff --git a/arch/mips/netlogic/xlp/ahci-init-xlp2.c b/arch/mips/netlogic/xlp/ahci-init-xlp2.c new file mode 100644 index 000000000000..c83dbf3689e2 --- /dev/null +++ b/arch/mips/netlogic/xlp/ahci-init-xlp2.c @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2003-2014 Broadcom Corporation + * All Rights Reserved + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the Broadcom + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/dma-mapping.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/irq.h> +#include <linux/bitops.h> +#include <linux/pci_ids.h> +#include <linux/nodemask.h> + +#include <asm/cpu.h> +#include <asm/mipsregs.h> + +#include <asm/netlogic/common.h> +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/mips-extns.h> +#include <asm/netlogic/xlp-hal/xlp.h> +#include <asm/netlogic/xlp-hal/iomap.h> + +#define SATA_CTL 0x0 +#define SATA_STATUS 0x1 /* Status Reg */ +#define SATA_INT 0x2 /* Interrupt Reg */ +#define SATA_INT_MASK 0x3 /* Interrupt Mask Reg */ +#define SATA_BIU_TIMEOUT 0x4 +#define AXIWRSPERRLOG 0x5 +#define AXIRDSPERRLOG 0x6 +#define BiuTimeoutLow 0x7 +#define BiuTimeoutHi 0x8 +#define BiuSlvErLow 0x9 +#define BiuSlvErHi 0xa +#define IO_CONFIG_SWAP_DIS 0xb +#define CR_REG_TIMER 0xc +#define CORE_ID 0xd +#define AXI_SLAVE_OPT1 0xe +#define PHY_MEM_ACCESS 0xf +#define PHY0_CNTRL 0x10 +#define PHY0_STAT 0x11 +#define PHY0_RX_ALIGN 0x12 +#define PHY0_RX_EQ_LO 0x13 +#define PHY0_RX_EQ_HI 0x14 +#define PHY0_BIST_LOOP 0x15 +#define PHY1_CNTRL 0x16 +#define PHY1_STAT 0x17 +#define PHY1_RX_ALIGN 0x18 +#define PHY1_RX_EQ_LO 0x19 +#define PHY1_RX_EQ_HI 0x1a +#define PHY1_BIST_LOOP 0x1b +#define RdExBase 0x1c +#define RdExLimit 0x1d +#define CacheAllocBase 0x1e +#define CacheAllocLimit 0x1f +#define BiuSlaveCmdGstNum 0x20 + +/*SATA_CTL Bits */ +#define SATA_RST_N BIT(0) /* Active low reset sata_core phy */ +#define SataCtlReserve0 BIT(1) +#define M_CSYSREQ BIT(2) /* AXI master low power, not used */ +#define S_CSYSREQ BIT(3) /* AXI slave low power, not used */ +#define P0_CP_DET BIT(8) /* Reserved, bring in from pad */ +#define P0_MP_SW BIT(9) /* Mech Switch */ +#define P0_DISABLE BIT(10) /* disable p0 */ +#define P0_ACT_LED_EN BIT(11) /* Active LED enable */ +#define P0_IRST_HARD_SYNTH BIT(12) /* PHY hard synth reset */ +#define P0_IRST_HARD_TXRX BIT(13) /* PHY lane hard reset */ +#define P0_IRST_POR BIT(14) /* PHY power on reset*/ +#define P0_IPDTXL BIT(15) /* PHY Tx lane dis/power down */ +#define P0_IPDRXL BIT(16) /* PHY Rx lane dis/power down */ +#define P0_IPDIPDMSYNTH BIT(17) /* PHY synthesizer dis/porwer down */ +#define P0_CP_POD_EN BIT(18) /* CP_POD enable */ +#define P0_AT_BYPASS BIT(19) /* P0 address translation by pass */ +#define P1_CP_DET BIT(20) /* Reserved,Cold Detect */ +#define P1_MP_SW BIT(21) /* Mech Switch */ +#define P1_DISABLE BIT(22) /* disable p1 */ +#define P1_ACT_LED_EN BIT(23) /* Active LED enable */ +#define P1_IRST_HARD_SYNTH BIT(24) /* PHY hard synth reset */ +#define P1_IRST_HARD_TXRX BIT(25) /* PHY lane hard reset */ +#define P1_IRST_POR BIT(26) /* PHY power on reset*/ +#define P1_IPDTXL BIT(27) /* PHY Tx lane dis/porwer down */ +#define P1_IPDRXL BIT(28) /* PHY Rx lane dis/porwer down */ +#define P1_IPDIPDMSYNTH BIT(29) /* PHY synthesizer dis/porwer down */ +#define P1_CP_POD_EN BIT(30) +#define P1_AT_BYPASS BIT(31) /* P1 address translation by pass */ + +/* Status register */ +#define M_CACTIVE BIT(0) /* m_cactive, not used */ +#define S_CACTIVE BIT(1) /* s_cactive, not used */ +#define P0_PHY_READY BIT(8) /* phy is ready */ +#define P0_CP_POD BIT(9) /* Cold PowerOn */ +#define P0_SLUMBER BIT(10) /* power mode slumber */ +#define P0_PATIAL BIT(11) /* power mode patial */ +#define P0_PHY_SIG_DET BIT(12) /* phy dignal detect */ +#define P0_PHY_CALI BIT(13) /* phy calibration done */ +#define P1_PHY_READY BIT(16) /* phy is ready */ +#define P1_CP_POD BIT(17) /* Cold PowerOn */ +#define P1_SLUMBER BIT(18) /* power mode slumber */ +#define P1_PATIAL BIT(19) /* power mode patial */ +#define P1_PHY_SIG_DET BIT(20) /* phy dignal detect */ +#define P1_PHY_CALI BIT(21) /* phy calibration done */ + +/* SATA CR_REG_TIMER bits */ +#define CR_TIME_SCALE (0x1000 << 0) + +/* SATA PHY specific registers start and end address */ +#define RXCDRCALFOSC0 0x0065 +#define CALDUTY 0x006e +#define RXDPIF 0x8065 +#define PPMDRIFTMAX_HI 0x80A4 + +#define nlm_read_sata_reg(b, r) nlm_read_reg(b, r) +#define nlm_write_sata_reg(b, r, v) nlm_write_reg(b, r, v) +#define nlm_get_sata_pcibase(node) \ + nlm_pcicfg_base(XLP9XX_IO_SATA_OFFSET(node)) +#define nlm_get_sata_regbase(node) \ + (nlm_get_sata_pcibase(node) + 0x100) + +/* SATA PHY config for register block 1 0x0065 .. 0x006e */ +static const u8 sata_phy_config1[] = { + 0xC9, 0xC9, 0x07, 0x07, 0x18, 0x18, 0x01, 0x01, 0x22, 0x00 +}; + +/* SATA PHY config for register block 2 0x0x8065 .. 0x0x80A4 */ +static const u8 sata_phy_config2[] = { + 0xAA, 0x00, 0x4C, 0xC9, 0xC9, 0x07, 0x07, 0x18, + 0x18, 0x05, 0x0C, 0x10, 0x00, 0x10, 0x00, 0xFF, + 0xCF, 0xF7, 0xE1, 0xF5, 0xFD, 0xFD, 0xFF, 0xFF, + 0xFF, 0xFF, 0xE3, 0xE7, 0xDB, 0xF5, 0xFD, 0xFD, + 0xF5, 0xF5, 0xFF, 0xFF, 0xE3, 0xE7, 0xDB, 0xF5, + 0xFD, 0xFD, 0xF5, 0xF5, 0xFF, 0xFF, 0xFF, 0xF5, + 0x3F, 0x00, 0x32, 0x00, 0x03, 0x01, 0x05, 0x05, + 0x04, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x04, +}; + +const int sata_phy_debug = 0; /* set to verify PHY writes */ + +static void sata_clear_glue_reg(u64 regbase, u32 off, u32 bit) +{ + u32 reg_val; + + reg_val = nlm_read_sata_reg(regbase, off); + nlm_write_sata_reg(regbase, off, (reg_val & ~bit)); +} + +static void sata_set_glue_reg(u64 regbase, u32 off, u32 bit) +{ + u32 reg_val; + + reg_val = nlm_read_sata_reg(regbase, off); + nlm_write_sata_reg(regbase, off, (reg_val | bit)); +} + +static void write_phy_reg(u64 regbase, u32 addr, u32 physel, u8 data) +{ + nlm_write_sata_reg(regbase, PHY_MEM_ACCESS, + (1u << 31) | (physel << 24) | (data << 16) | addr); + udelay(850); +} + +static u8 read_phy_reg(u64 regbase, u32 addr, u32 physel) +{ + u32 val; + + nlm_write_sata_reg(regbase, PHY_MEM_ACCESS, + (0 << 31) | (physel << 24) | (0 << 16) | addr); + udelay(850); + val = nlm_read_sata_reg(regbase, PHY_MEM_ACCESS); + return (val >> 16) & 0xff; +} + +static void config_sata_phy(u64 regbase) +{ + u32 port, i, reg; + + for (port = 0; port < 2; port++) { + for (i = 0, reg = RXCDRCALFOSC0; reg <= CALDUTY; reg++, i++) + write_phy_reg(regbase, reg, port, sata_phy_config1[i]); + + for (i = 0, reg = RXDPIF; reg <= PPMDRIFTMAX_HI; reg++, i++) + write_phy_reg(regbase, reg, port, sata_phy_config2[i]); + } +} + +static void check_phy_register(u64 regbase, u32 addr, u32 physel, u8 xdata) +{ + u8 data; + + data = read_phy_reg(regbase, addr, physel); + pr_info("PHY read addr = 0x%x physel = %d data = 0x%x %s\n", + addr, physel, data, data == xdata ? "TRUE" : "FALSE"); +} + +static void verify_sata_phy_config(u64 regbase) +{ + u32 port, i, reg; + + for (port = 0; port < 2; port++) { + for (i = 0, reg = RXCDRCALFOSC0; reg <= CALDUTY; reg++, i++) + check_phy_register(regbase, reg, port, + sata_phy_config1[i]); + + for (i = 0, reg = RXDPIF; reg <= PPMDRIFTMAX_HI; reg++, i++) + check_phy_register(regbase, reg, port, + sata_phy_config2[i]); + } +} + +static void nlm_sata_firmware_init(int node) +{ + u32 reg_val; + u64 regbase; + int n; + + pr_info("Initializing XLP9XX On-chip AHCI...\n"); + regbase = nlm_get_sata_regbase(node); + + /* Reset port0 */ + sata_clear_glue_reg(regbase, SATA_CTL, P0_IRST_POR); + sata_clear_glue_reg(regbase, SATA_CTL, P0_IRST_HARD_TXRX); + sata_clear_glue_reg(regbase, SATA_CTL, P0_IRST_HARD_SYNTH); + sata_clear_glue_reg(regbase, SATA_CTL, P0_IPDTXL); + sata_clear_glue_reg(regbase, SATA_CTL, P0_IPDRXL); + sata_clear_glue_reg(regbase, SATA_CTL, P0_IPDIPDMSYNTH); + + /* port1 */ + sata_clear_glue_reg(regbase, SATA_CTL, P1_IRST_POR); + sata_clear_glue_reg(regbase, SATA_CTL, P1_IRST_HARD_TXRX); + sata_clear_glue_reg(regbase, SATA_CTL, P1_IRST_HARD_SYNTH); + sata_clear_glue_reg(regbase, SATA_CTL, P1_IPDTXL); + sata_clear_glue_reg(regbase, SATA_CTL, P1_IPDRXL); + sata_clear_glue_reg(regbase, SATA_CTL, P1_IPDIPDMSYNTH); + udelay(300); + + /* Set PHY */ + sata_set_glue_reg(regbase, SATA_CTL, P0_IPDTXL); + sata_set_glue_reg(regbase, SATA_CTL, P0_IPDRXL); + sata_set_glue_reg(regbase, SATA_CTL, P0_IPDIPDMSYNTH); + sata_set_glue_reg(regbase, SATA_CTL, P1_IPDTXL); + sata_set_glue_reg(regbase, SATA_CTL, P1_IPDRXL); + sata_set_glue_reg(regbase, SATA_CTL, P1_IPDIPDMSYNTH); + + udelay(1000); + sata_set_glue_reg(regbase, SATA_CTL, P0_IRST_POR); + udelay(1000); + sata_set_glue_reg(regbase, SATA_CTL, P1_IRST_POR); + udelay(1000); + + /* setup PHY */ + config_sata_phy(regbase); + if (sata_phy_debug) + verify_sata_phy_config(regbase); + + udelay(1000); + sata_set_glue_reg(regbase, SATA_CTL, P0_IRST_HARD_TXRX); + sata_set_glue_reg(regbase, SATA_CTL, P0_IRST_HARD_SYNTH); + sata_set_glue_reg(regbase, SATA_CTL, P1_IRST_HARD_TXRX); + sata_set_glue_reg(regbase, SATA_CTL, P1_IRST_HARD_SYNTH); + udelay(300); + + /* Override reset in serial PHY mode */ + sata_set_glue_reg(regbase, CR_REG_TIMER, CR_TIME_SCALE); + /* Set reset SATA */ + sata_set_glue_reg(regbase, SATA_CTL, SATA_RST_N); + sata_set_glue_reg(regbase, SATA_CTL, M_CSYSREQ); + sata_set_glue_reg(regbase, SATA_CTL, S_CSYSREQ); + + pr_debug("Waiting for PHYs to come up.\n"); + n = 10000; + do { + reg_val = nlm_read_sata_reg(regbase, SATA_STATUS); + if ((reg_val & P1_PHY_READY) && (reg_val & P0_PHY_READY)) + break; + udelay(10); + } while (--n > 0); + + if (reg_val & P0_PHY_READY) + pr_info("PHY0 is up.\n"); + else + pr_info("PHY0 is down.\n"); + if (reg_val & P1_PHY_READY) + pr_info("PHY1 is up.\n"); + else + pr_info("PHY1 is down.\n"); + + pr_info("XLP AHCI Init Done.\n"); +} + +static int __init nlm_ahci_init(void) +{ + int node; + + if (!cpu_is_xlp9xx()) + return 0; + for (node = 0; node < NLM_NR_NODES; node++) + if (nlm_node_present(node)) + nlm_sata_firmware_init(node); + return 0; +} + +static void nlm_sata_intr_ack(struct irq_data *data) +{ + u64 regbase; + u32 val; + int node; + + node = data->irq / NLM_IRQS_PER_NODE; + regbase = nlm_get_sata_regbase(node); + val = nlm_read_sata_reg(regbase, SATA_INT); + sata_set_glue_reg(regbase, SATA_INT, val); +} + +static void nlm_sata_fixup_bar(struct pci_dev *dev) +{ + dev->resource[5] = dev->resource[0]; + memset(&dev->resource[0], 0, sizeof(dev->resource[0])); +} + +static void nlm_sata_fixup_final(struct pci_dev *dev) +{ + u32 val; + u64 regbase; + int node; + + /* Find end bridge function to find node */ + node = xlp_socdev_to_node(dev); + regbase = nlm_get_sata_regbase(node); + + /* clear pending interrupts and then enable them */ + val = nlm_read_sata_reg(regbase, SATA_INT); + sata_set_glue_reg(regbase, SATA_INT, val); + + /* Enable only the core interrupt */ + sata_set_glue_reg(regbase, SATA_INT_MASK, 0x1); + + dev->irq = nlm_irq_to_xirq(node, PIC_SATA_IRQ); + nlm_set_pic_extra_ack(node, PIC_SATA_IRQ, nlm_sata_intr_ack); +} + +arch_initcall(nlm_ahci_init); + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_XLP9XX_SATA, + nlm_sata_fixup_bar); + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_XLP9XX_SATA, + nlm_sata_fixup_final); diff --git a/arch/mips/netlogic/xlp/ahci-init.c b/arch/mips/netlogic/xlp/ahci-init.c new file mode 100644 index 000000000000..a9d0fae02103 --- /dev/null +++ b/arch/mips/netlogic/xlp/ahci-init.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2003-2014 Broadcom Corporation + * All Rights Reserved + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the Broadcom + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/dma-mapping.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/irq.h> +#include <linux/bitops.h> + +#include <asm/cpu.h> +#include <asm/mipsregs.h> + +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/xlp-hal/xlp.h> +#include <asm/netlogic/common.h> +#include <asm/netlogic/xlp-hal/iomap.h> +#include <asm/netlogic/mips-extns.h> + +#define SATA_CTL 0x0 +#define SATA_STATUS 0x1 /* Status Reg */ +#define SATA_INT 0x2 /* Interrupt Reg */ +#define SATA_INT_MASK 0x3 /* Interrupt Mask Reg */ +#define SATA_CR_REG_TIMER 0x4 /* PHY Conrol Timer Reg */ +#define SATA_CORE_ID 0x5 /* Core ID Reg */ +#define SATA_AXI_SLAVE_OPT1 0x6 /* AXI Slave Options Reg */ +#define SATA_PHY_LOS_LEV 0x7 /* PHY LOS Level Reg */ +#define SATA_PHY_MULTI 0x8 /* PHY Multiplier Reg */ +#define SATA_PHY_CLK_SEL 0x9 /* Clock Select Reg */ +#define SATA_PHY_AMP1_GEN1 0xa /* PHY Transmit Amplitude Reg 1 */ +#define SATA_PHY_AMP1_GEN2 0xb /* PHY Transmit Amplitude Reg 2 */ +#define SATA_PHY_AMP1_GEN3 0xc /* PHY Transmit Amplitude Reg 3 */ +#define SATA_PHY_PRE1 0xd /* PHY Transmit Preemphasis Reg 1 */ +#define SATA_PHY_PRE2 0xe /* PHY Transmit Preemphasis Reg 2 */ +#define SATA_PHY_PRE3 0xf /* PHY Transmit Preemphasis Reg 3 */ +#define SATA_SPDMODE 0x10 /* Speed Mode Reg */ +#define SATA_REFCLK 0x11 /* Reference Clock Control Reg */ +#define SATA_BYTE_SWAP_DIS 0x12 /* byte swap disable */ + +/*SATA_CTL Bits */ +#define SATA_RST_N BIT(0) +#define PHY0_RESET_N BIT(16) +#define PHY1_RESET_N BIT(17) +#define PHY2_RESET_N BIT(18) +#define PHY3_RESET_N BIT(19) +#define M_CSYSREQ BIT(2) +#define S_CSYSREQ BIT(3) + +/*SATA_STATUS Bits */ +#define P0_PHY_READY BIT(4) +#define P1_PHY_READY BIT(5) +#define P2_PHY_READY BIT(6) +#define P3_PHY_READY BIT(7) + +#define nlm_read_sata_reg(b, r) nlm_read_reg(b, r) +#define nlm_write_sata_reg(b, r, v) nlm_write_reg(b, r, v) +#define nlm_get_sata_pcibase(node) \ + nlm_pcicfg_base(XLP_IO_SATA_OFFSET(node)) +/* SATA device specific configuration registers are starts at 0x900 offset */ +#define nlm_get_sata_regbase(node) \ + (nlm_get_sata_pcibase(node) + 0x900) + +static void sata_clear_glue_reg(uint64_t regbase, uint32_t off, uint32_t bit) +{ + uint32_t reg_val; + + reg_val = nlm_read_sata_reg(regbase, off); + nlm_write_sata_reg(regbase, off, (reg_val & ~bit)); +} + +static void sata_set_glue_reg(uint64_t regbase, uint32_t off, uint32_t bit) +{ + uint32_t reg_val; + + reg_val = nlm_read_sata_reg(regbase, off); + nlm_write_sata_reg(regbase, off, (reg_val | bit)); +} + +static void nlm_sata_firmware_init(int node) +{ + uint32_t reg_val; + uint64_t regbase; + int i; + + pr_info("XLP AHCI Initialization started.\n"); + regbase = nlm_get_sata_regbase(node); + + /* Reset SATA */ + sata_clear_glue_reg(regbase, SATA_CTL, SATA_RST_N); + /* Reset PHY */ + sata_clear_glue_reg(regbase, SATA_CTL, + (PHY3_RESET_N | PHY2_RESET_N + | PHY1_RESET_N | PHY0_RESET_N)); + + /* Set SATA */ + sata_set_glue_reg(regbase, SATA_CTL, SATA_RST_N); + /* Set PHY */ + sata_set_glue_reg(regbase, SATA_CTL, + (PHY3_RESET_N | PHY2_RESET_N + | PHY1_RESET_N | PHY0_RESET_N)); + + pr_debug("Waiting for PHYs to come up.\n"); + i = 0; + do { + reg_val = nlm_read_sata_reg(regbase, SATA_STATUS); + i++; + } while (((reg_val & 0xF0) != 0xF0) && (i < 10000)); + + for (i = 0; i < 4; i++) { + if (reg_val & (P0_PHY_READY << i)) + pr_info("PHY%d is up.\n", i); + else + pr_info("PHY%d is down.\n", i); + } + + pr_info("XLP AHCI init done.\n"); +} + +static int __init nlm_ahci_init(void) +{ + int node = 0; + int chip = read_c0_prid() & PRID_REV_MASK; + + if (chip == PRID_IMP_NETLOGIC_XLP3XX) + nlm_sata_firmware_init(node); + return 0; +} + +static void nlm_sata_intr_ack(struct irq_data *data) +{ + uint32_t val = 0; + uint64_t regbase; + + regbase = nlm_get_sata_regbase(nlm_nodeid()); + val = nlm_read_sata_reg(regbase, SATA_INT); + sata_set_glue_reg(regbase, SATA_INT, val); +} + +static void nlm_sata_fixup_bar(struct pci_dev *dev) +{ + /* + * The AHCI resource is in BAR 0, move it to + * BAR 5, where it is expected + */ + dev->resource[5] = dev->resource[0]; + memset(&dev->resource[0], 0, sizeof(dev->resource[0])); +} + +static void nlm_sata_fixup_final(struct pci_dev *dev) +{ + uint32_t val; + uint64_t regbase; + int node = 0; /* XLP3XX does not support multi-node */ + + regbase = nlm_get_sata_regbase(node); + + /* clear pending interrupts and then enable them */ + val = nlm_read_sata_reg(regbase, SATA_INT); + sata_set_glue_reg(regbase, SATA_INT, val); + + /* Mask the core interrupt. If all the interrupts + * are enabled there are spurious interrupt flow + * happening, to avoid only enable core interrupt + * mask. + */ + sata_set_glue_reg(regbase, SATA_INT_MASK, 0x1); + + dev->irq = PIC_SATA_IRQ; + nlm_set_pic_extra_ack(node, PIC_SATA_IRQ, nlm_sata_intr_ack); +} + +arch_initcall(nlm_ahci_init); + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_SATA, + nlm_sata_fixup_bar); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_SATA, + nlm_sata_fixup_final); diff --git a/arch/mips/netlogic/xlp/dt.c b/arch/mips/netlogic/xlp/dt.c index bdde33147bce..7cc46032b28e 100644 --- a/arch/mips/netlogic/xlp/dt.c +++ b/arch/mips/netlogic/xlp/dt.c @@ -48,9 +48,10 @@ static void *xlp_fdt_blob; void __init *xlp_dt_init(void *fdtp) { if (!fdtp) { - switch (current_cpu_data.processor_id & 0xff00) { + switch (current_cpu_data.processor_id & PRID_IMP_MASK) { #ifdef CONFIG_DT_XLP_GVP case PRID_IMP_NETLOGIC_XLP9XX: + case PRID_IMP_NETLOGIC_XLP5XX: fdtp = __dtb_xlp_gvp_begin; break; #endif diff --git a/arch/mips/netlogic/xlp/nlm_hal.c b/arch/mips/netlogic/xlp/nlm_hal.c index 997cd9ee10de..bc24beb3a426 100644 --- a/arch/mips/netlogic/xlp/nlm_hal.c +++ b/arch/mips/netlogic/xlp/nlm_hal.c @@ -54,6 +54,8 @@ void nlm_node_init(int node) struct nlm_soc_info *nodep; nodep = nlm_get_node(node); + if (node == 0) + nodep->coremask = 1; /* node 0, boot cpu */ nodep->sysbase = nlm_get_sys_regbase(node); nodep->picbase = nlm_get_pic_regbase(node); nodep->ebase = read_c0_ebase() & (~((1 << 12) - 1)); @@ -64,31 +66,39 @@ void nlm_node_init(int node) spin_lock_init(&nodep->piclock); } -int nlm_irq_to_irt(int irq) +static int xlp9xx_irq_to_irt(int irq) +{ + switch (irq) { + case PIC_GPIO_IRQ: + return 12; + case PIC_9XX_XHCI_0_IRQ: + return 114; + case PIC_9XX_XHCI_1_IRQ: + return 115; + case PIC_UART_0_IRQ: + return 133; + case PIC_UART_1_IRQ: + return 134; + case PIC_SATA_IRQ: + return 143; + case PIC_SPI_IRQ: + return 152; + case PIC_MMC_IRQ: + return 153; + case PIC_PCIE_LINK_LEGACY_IRQ(0): + case PIC_PCIE_LINK_LEGACY_IRQ(1): + case PIC_PCIE_LINK_LEGACY_IRQ(2): + case PIC_PCIE_LINK_LEGACY_IRQ(3): + return 191 + irq - PIC_PCIE_LINK_LEGACY_IRQ_BASE; + } + return -1; +} + +static int xlp_irq_to_irt(int irq) { uint64_t pcibase; int devoff, irt; - /* bypass for 9xx */ - if (cpu_is_xlp9xx()) { - switch (irq) { - case PIC_9XX_XHCI_0_IRQ: - return 114; - case PIC_9XX_XHCI_1_IRQ: - return 115; - case PIC_UART_0_IRQ: - return 133; - case PIC_UART_1_IRQ: - return 134; - case PIC_PCIE_LINK_LEGACY_IRQ(0): - case PIC_PCIE_LINK_LEGACY_IRQ(1): - case PIC_PCIE_LINK_LEGACY_IRQ(2): - case PIC_PCIE_LINK_LEGACY_IRQ(3): - return 191 + irq - PIC_PCIE_LINK_LEGACY_IRQ_BASE; - } - return -1; - } - devoff = 0; switch (irq) { case PIC_UART_0_IRQ: @@ -98,7 +108,7 @@ int nlm_irq_to_irt(int irq) devoff = XLP_IO_UART1_OFFSET(0); break; case PIC_MMC_IRQ: - devoff = XLP_IO_SD_OFFSET(0); + devoff = XLP_IO_MMC_OFFSET(0); break; case PIC_I2C_0_IRQ: /* I2C will be fixed up */ case PIC_I2C_1_IRQ: @@ -109,6 +119,18 @@ int nlm_irq_to_irt(int irq) else devoff = XLP_IO_I2C0_OFFSET(0); break; + case PIC_SATA_IRQ: + devoff = XLP_IO_SATA_OFFSET(0); + break; + case PIC_GPIO_IRQ: + devoff = XLP_IO_GPIO_OFFSET(0); + break; + case PIC_NAND_IRQ: + devoff = XLP_IO_NAND_OFFSET(0); + break; + case PIC_SPI_IRQ: + devoff = XLP_IO_SPI_OFFSET(0); + break; default: if (cpu_is_xlpii()) { switch (irq) { @@ -164,61 +186,123 @@ int nlm_irq_to_irt(int irq) /* HW bug, PCI IRT entries are bad on early silicon, fix */ irt = PIC_IRT_PCIE_LINK_INDEX(irq - PIC_PCIE_LINK_LEGACY_IRQ_BASE); - } else if (irq >= PIC_PCIE_LINK_MSI_IRQ(0) && - irq <= PIC_PCIE_LINK_MSI_IRQ(3)) { - irt = -2; - } else if (irq >= PIC_PCIE_MSIX_IRQ(0) && - irq <= PIC_PCIE_MSIX_IRQ(3)) { - irt = -2; } else { irt = -1; } return irt; } -unsigned int nlm_get_core_frequency(int node, int core) +int nlm_irq_to_irt(int irq) { - unsigned int pll_divf, pll_divr, dfs_div, ext_div; - unsigned int rstval, dfsval, denom; - uint64_t num, sysbase; + /* return -2 for irqs without 1-1 mapping */ + if (irq >= PIC_PCIE_LINK_MSI_IRQ(0) && irq <= PIC_PCIE_LINK_MSI_IRQ(3)) + return -2; + if (irq >= PIC_PCIE_MSIX_IRQ(0) && irq <= PIC_PCIE_MSIX_IRQ(3)) + return -2; - sysbase = nlm_get_node(node)->sysbase; if (cpu_is_xlp9xx()) - rstval = nlm_read_sys_reg(sysbase, SYS_9XX_POWER_ON_RESET_CFG); + return xlp9xx_irq_to_irt(irq); else - rstval = nlm_read_sys_reg(sysbase, SYS_POWER_ON_RESET_CFG); - if (cpu_is_xlpii()) { - num = 1000000ULL * (400 * 3 + 100 * (rstval >> 26)); - denom = 3; + return xlp_irq_to_irt(irq); +} + +static unsigned int nlm_xlp2_get_core_frequency(int node, int core) +{ + unsigned int pll_post_div, ctrl_val0, ctrl_val1, denom; + uint64_t num, sysbase, clockbase; + + if (cpu_is_xlp9xx()) { + clockbase = nlm_get_clock_regbase(node); + ctrl_val0 = nlm_read_sys_reg(clockbase, + SYS_9XX_CPU_PLL_CTRL0(core)); + ctrl_val1 = nlm_read_sys_reg(clockbase, + SYS_9XX_CPU_PLL_CTRL1(core)); } else { - dfsval = nlm_read_sys_reg(sysbase, SYS_CORE_DFS_DIV_VALUE); - pll_divf = ((rstval >> 10) & 0x7f) + 1; - pll_divr = ((rstval >> 8) & 0x3) + 1; - ext_div = ((rstval >> 30) & 0x3) + 1; - dfs_div = ((dfsval >> (core * 4)) & 0xf) + 1; - - num = 800000000ULL * pll_divf; - denom = 3 * pll_divr * ext_div * dfs_div; + sysbase = nlm_get_node(node)->sysbase; + ctrl_val0 = nlm_read_sys_reg(sysbase, + SYS_CPU_PLL_CTRL0(core)); + ctrl_val1 = nlm_read_sys_reg(sysbase, + SYS_CPU_PLL_CTRL1(core)); + } + + /* Find PLL post divider value */ + switch ((ctrl_val0 >> 24) & 0x7) { + case 1: + pll_post_div = 2; + break; + case 3: + pll_post_div = 4; + break; + case 7: + pll_post_div = 8; + break; + case 6: + pll_post_div = 16; + break; + case 0: + default: + pll_post_div = 1; + break; } + + num = 1000000ULL * (400 * 3 + 100 * (ctrl_val1 & 0x3f)); + denom = 3 * pll_post_div; do_div(num, denom); + return (unsigned int)num; } -/* Calculate Frequency to the PIC from PLL. - * freq_out = ( ref_freq/2 * (6 + ctrl2[7:0]) + ctrl2[20:8]/2^13 ) / - * ((2^ctrl0[7:5]) * Table(ctrl0[26:24])) +static unsigned int nlm_xlp_get_core_frequency(int node, int core) +{ + unsigned int pll_divf, pll_divr, dfs_div, ext_div; + unsigned int rstval, dfsval, denom; + uint64_t num, sysbase; + + sysbase = nlm_get_node(node)->sysbase; + rstval = nlm_read_sys_reg(sysbase, SYS_POWER_ON_RESET_CFG); + dfsval = nlm_read_sys_reg(sysbase, SYS_CORE_DFS_DIV_VALUE); + pll_divf = ((rstval >> 10) & 0x7f) + 1; + pll_divr = ((rstval >> 8) & 0x3) + 1; + ext_div = ((rstval >> 30) & 0x3) + 1; + dfs_div = ((dfsval >> (core * 4)) & 0xf) + 1; + + num = 800000000ULL * pll_divf; + denom = 3 * pll_divr * ext_div * dfs_div; + do_div(num, denom); + + return (unsigned int)num; +} + +unsigned int nlm_get_core_frequency(int node, int core) +{ + if (cpu_is_xlpii()) + return nlm_xlp2_get_core_frequency(node, core); + else + return nlm_xlp_get_core_frequency(node, core); +} + +/* + * Calculate PIC frequency from PLL registers. + * freq_out = (ref_freq/2 * (6 + ctrl2[7:0]) + ctrl2[20:8]/2^13) / + * ((2^ctrl0[7:5]) * Table(ctrl0[26:24])) */ -static unsigned int nlm_2xx_get_pic_frequency(int node) +static unsigned int nlm_xlp2_get_pic_frequency(int node) { - u32 ctrl_val0, ctrl_val2, vco_post_div, pll_post_div; + u32 ctrl_val0, ctrl_val2, vco_post_div, pll_post_div, cpu_xlp9xx; u32 mdiv, fdiv, pll_out_freq_den, reg_select, ref_div, pic_div; - u64 ref_clk, sysbase, pll_out_freq_num, ref_clk_select; + u64 sysbase, pll_out_freq_num, ref_clk_select, clockbase, ref_clk; sysbase = nlm_get_node(node)->sysbase; + clockbase = nlm_get_clock_regbase(node); + cpu_xlp9xx = cpu_is_xlp9xx(); /* Find ref_clk_base */ - ref_clk_select = - (nlm_read_sys_reg(sysbase, SYS_POWER_ON_RESET_CFG) >> 18) & 0x3; + if (cpu_xlp9xx) + ref_clk_select = (nlm_read_sys_reg(sysbase, + SYS_9XX_POWER_ON_RESET_CFG) >> 18) & 0x3; + else + ref_clk_select = (nlm_read_sys_reg(sysbase, + SYS_POWER_ON_RESET_CFG) >> 18) & 0x3; switch (ref_clk_select) { case 0: ref_clk = 200000000ULL; @@ -239,30 +323,70 @@ static unsigned int nlm_2xx_get_pic_frequency(int node) } /* Find the clock source PLL device for PIC */ - reg_select = (nlm_read_sys_reg(sysbase, SYS_CLK_DEV_SEL) >> 22) & 0x3; - switch (reg_select) { - case 0: - ctrl_val0 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL0); - ctrl_val2 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL2); - break; - case 1: - ctrl_val0 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL0_DEVX(0)); - ctrl_val2 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL2_DEVX(0)); - break; - case 2: - ctrl_val0 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL0_DEVX(1)); - ctrl_val2 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL2_DEVX(1)); - break; - case 3: - ctrl_val0 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL0_DEVX(2)); - ctrl_val2 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL2_DEVX(2)); - break; + if (cpu_xlp9xx) { + reg_select = nlm_read_sys_reg(clockbase, + SYS_9XX_CLK_DEV_SEL) & 0x3; + switch (reg_select) { + case 0: + ctrl_val0 = nlm_read_sys_reg(clockbase, + SYS_9XX_PLL_CTRL0); + ctrl_val2 = nlm_read_sys_reg(clockbase, + SYS_9XX_PLL_CTRL2); + break; + case 1: + ctrl_val0 = nlm_read_sys_reg(clockbase, + SYS_9XX_PLL_CTRL0_DEVX(0)); + ctrl_val2 = nlm_read_sys_reg(clockbase, + SYS_9XX_PLL_CTRL2_DEVX(0)); + break; + case 2: + ctrl_val0 = nlm_read_sys_reg(clockbase, + SYS_9XX_PLL_CTRL0_DEVX(1)); + ctrl_val2 = nlm_read_sys_reg(clockbase, + SYS_9XX_PLL_CTRL2_DEVX(1)); + break; + case 3: + ctrl_val0 = nlm_read_sys_reg(clockbase, + SYS_9XX_PLL_CTRL0_DEVX(2)); + ctrl_val2 = nlm_read_sys_reg(clockbase, + SYS_9XX_PLL_CTRL2_DEVX(2)); + break; + } + } else { + reg_select = (nlm_read_sys_reg(sysbase, + SYS_CLK_DEV_SEL) >> 22) & 0x3; + switch (reg_select) { + case 0: + ctrl_val0 = nlm_read_sys_reg(sysbase, + SYS_PLL_CTRL0); + ctrl_val2 = nlm_read_sys_reg(sysbase, + SYS_PLL_CTRL2); + break; + case 1: + ctrl_val0 = nlm_read_sys_reg(sysbase, + SYS_PLL_CTRL0_DEVX(0)); + ctrl_val2 = nlm_read_sys_reg(sysbase, + SYS_PLL_CTRL2_DEVX(0)); + break; + case 2: + ctrl_val0 = nlm_read_sys_reg(sysbase, + SYS_PLL_CTRL0_DEVX(1)); + ctrl_val2 = nlm_read_sys_reg(sysbase, + SYS_PLL_CTRL2_DEVX(1)); + break; + case 3: + ctrl_val0 = nlm_read_sys_reg(sysbase, + SYS_PLL_CTRL0_DEVX(2)); + ctrl_val2 = nlm_read_sys_reg(sysbase, + SYS_PLL_CTRL2_DEVX(2)); + break; + } } vco_post_div = (ctrl_val0 >> 5) & 0x7; pll_post_div = (ctrl_val0 >> 24) & 0x7; mdiv = ctrl_val2 & 0xff; - fdiv = (ctrl_val2 >> 8) & 0xfff; + fdiv = (ctrl_val2 >> 8) & 0x1fff; /* Find PLL post divider value */ switch (pll_post_div) { @@ -292,7 +416,12 @@ static unsigned int nlm_2xx_get_pic_frequency(int node) do_div(pll_out_freq_num, pll_out_freq_den); /* PIC post divider, which happens after PLL */ - pic_div = (nlm_read_sys_reg(sysbase, SYS_CLK_DEV_DIV) >> 22) & 0x3; + if (cpu_xlp9xx) + pic_div = nlm_read_sys_reg(clockbase, + SYS_9XX_CLK_DEV_DIV) & 0x3; + else + pic_div = (nlm_read_sys_reg(sysbase, + SYS_CLK_DEV_DIV) >> 22) & 0x3; do_div(pll_out_freq_num, 1 << pic_div); return pll_out_freq_num; @@ -300,12 +429,8 @@ static unsigned int nlm_2xx_get_pic_frequency(int node) unsigned int nlm_get_pic_frequency(int node) { - /* TODO Has to calculate freq as like 2xx */ - if (cpu_is_xlp9xx()) - return 250000000; - if (cpu_is_xlpii()) - return nlm_2xx_get_pic_frequency(node); + return nlm_xlp2_get_pic_frequency(node); else return 133333333; } diff --git a/arch/mips/netlogic/xlp/setup.c b/arch/mips/netlogic/xlp/setup.c index 8c60a2dd9ef6..4fdd9fd29d1d 100644 --- a/arch/mips/netlogic/xlp/setup.c +++ b/arch/mips/netlogic/xlp/setup.c @@ -121,8 +121,9 @@ void __init plat_mem_setup(void) const char *get_system_type(void) { - switch (read_c0_prid() & 0xff00) { + switch (read_c0_prid() & PRID_IMP_MASK) { case PRID_IMP_NETLOGIC_XLP9XX: + case PRID_IMP_NETLOGIC_XLP5XX: case PRID_IMP_NETLOGIC_XLP2XX: return "Broadcom XLPII Series"; default: diff --git a/arch/mips/netlogic/xlp/wakeup.c b/arch/mips/netlogic/xlp/wakeup.c index 9a92617a2af5..e5f44d2605a8 100644 --- a/arch/mips/netlogic/xlp/wakeup.c +++ b/arch/mips/netlogic/xlp/wakeup.c @@ -135,11 +135,19 @@ static void xlp_enable_secondary_cores(const cpumask_t *wakeup_mask) if (cpu_is_xlp9xx()) { fusebase = nlm_get_fuse_regbase(n); fusemask = nlm_read_reg(fusebase, FUSE_9XX_DEVCFG6); - mask = 0xfffff; + switch (read_c0_prid() & PRID_IMP_MASK) { + case PRID_IMP_NETLOGIC_XLP5XX: + mask = 0xff; + break; + case PRID_IMP_NETLOGIC_XLP9XX: + default: + mask = 0xfffff; + break; + } } else { fusemask = nlm_read_sys_reg(nodep->sysbase, SYS_EFUSE_DEVICE_CFG_STATUS0); - switch (read_c0_prid() & 0xff00) { + switch (read_c0_prid() & PRID_IMP_MASK) { case PRID_IMP_NETLOGIC_XLP3XX: mask = 0xf; break; @@ -159,10 +167,6 @@ static void xlp_enable_secondary_cores(const cpumask_t *wakeup_mask) */ syscoremask = (1 << hweight32(~fusemask & mask)) - 1; - /* The boot cpu */ - if (n == 0) - nodep->coremask = 1; - pr_info("Node %d - SYS/FUSE coremask %x\n", n, syscoremask); for (core = 0; core < nlm_cores_per_node(); core++) { /* we will be on node 0 core 0 */ |