1
0
Fork 0

Merge remote-tracking branch 'origin/arch/qoriq' into arch/next

* origin/arch/qoriq: (17 commits)
  drivers: soc: fsl: add qixis driver
  Add APIs to setup HugeTLB mappings for USDPAA
  powerpc/pm: add sleep and deep sleep on QorIQ SoCs
  powerpc/cache: add cache flush operation for various e500
  powerpc/pm: Fix suspend=n in menuconfig for e500mc platforms.
  ...
5.4-rM2-2.2.x-imx-squashed
Dong Aisheng 2019-12-02 18:00:36 +08:00
commit 7e3b1c91d0
47 changed files with 2399 additions and 104 deletions

View File

@ -85,6 +85,22 @@ extern void __bad_udelay(void);
__const_udelay((n) * UDELAY_MULT)) : \
__udelay(n))
#define spin_event_timeout(condition, timeout, delay) \
({ \
typeof(condition) __ret; \
int i = 0; \
while (!(__ret = (condition)) && (i++ < timeout)) { \
if (delay) \
udelay(delay); \
else \
cpu_relax(); \
udelay(1); \
} \
if (!__ret) \
__ret = (condition); \
__ret; \
})
/* Loop-based definitions for assembly code. */
extern void __loop_delay(unsigned long loops);
extern void __loop_udelay(unsigned long usecs);

View File

@ -123,6 +123,7 @@ static inline u32 __raw_readl(const volatile void __iomem *addr)
#define MT_DEVICE_NONSHARED 1
#define MT_DEVICE_CACHED 2
#define MT_DEVICE_WC 3
#define MT_MEMORY_RW_NS 4
/*
* types 4 onwards can be found in asm/mach/map.h and are undefined
* for ioremap
@ -224,6 +225,34 @@ void __iomem *pci_remap_cfgspace(resource_size_t res_cookie, size_t size);
#endif
#endif
/* access ports */
#define setbits32(_addr, _v) iowrite32be(ioread32be(_addr) | (_v), (_addr))
#define clrbits32(_addr, _v) iowrite32be(ioread32be(_addr) & ~(_v), (_addr))
#define setbits16(_addr, _v) iowrite16be(ioread16be(_addr) | (_v), (_addr))
#define clrbits16(_addr, _v) iowrite16be(ioread16be(_addr) & ~(_v), (_addr))
#define setbits8(_addr, _v) iowrite8(ioread8(_addr) | (_v), (_addr))
#define clrbits8(_addr, _v) iowrite8(ioread8(_addr) & ~(_v), (_addr))
/* Clear and set bits in one shot. These macros can be used to clear and
* set multiple bits in a register using a single read-modify-write. These
* macros can also be used to set a multiple-bit bit pattern using a mask,
* by specifying the mask in the 'clear' parameter and the new bit pattern
* in the 'set' parameter.
*/
#define clrsetbits_be32(addr, clear, set) \
iowrite32be((ioread32be(addr) & ~(clear)) | (set), (addr))
#define clrsetbits_le32(addr, clear, set) \
iowrite32le((ioread32le(addr) & ~(clear)) | (set), (addr))
#define clrsetbits_be16(addr, clear, set) \
iowrite16be((ioread16be(addr) & ~(clear)) | (set), (addr))
#define clrsetbits_le16(addr, clear, set) \
iowrite16le((ioread16le(addr) & ~(clear)) | (set), (addr))
#define clrsetbits_8(addr, clear, set) \
iowrite8((ioread8(addr) & ~(clear)) | (set), (addr))
/*
* IO port access primitives
* -------------------------
@ -410,6 +439,8 @@ void __iomem *ioremap_wc(resource_size_t res_cookie, size_t size);
#define ioremap_wc ioremap_wc
#define ioremap_wt ioremap_wc
void __iomem *ioremap_cache_ns(resource_size_t res_cookie, size_t size);
void iounmap(volatile void __iomem *iomem_cookie);
#define iounmap iounmap

View File

@ -18,9 +18,9 @@ struct map_desc {
unsigned int type;
};
/* types 0-3 are defined in asm/io.h */
/* types 0-4 are defined in asm/io.h */
enum {
MT_UNCACHED = 4,
MT_UNCACHED = 5,
MT_CACHECLEAN,
MT_MINICLEAN,
MT_LOW_VECTORS,

View File

@ -116,6 +116,13 @@ extern pgprot_t pgprot_s2_device;
#define pgprot_noncached(prot) \
__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED)
#define pgprot_cached(prot) \
__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_DEV_CACHED)
#define pgprot_cached_ns(prot) \
__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_DEV_CACHED | \
L_PTE_MT_DEV_NONSHARED)
#define pgprot_writecombine(prot) \
__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE)

View File

@ -9,6 +9,7 @@
* reading the RTC at bootup, etc...
*/
#include <linux/clk-provider.h>
#include <linux/clockchips.h>
#include <linux/clocksource.h>
#include <linux/errno.h>
#include <linux/export.h>
@ -107,5 +108,7 @@ void __init time_init(void)
of_clk_init(NULL);
#endif
timer_probe();
tick_setup_hrtimer_broadcast();
}
}

View File

@ -2320,6 +2320,7 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
#endif
dev->archdata.dma_ops_setup = true;
}
EXPORT_SYMBOL(arch_setup_dma_ops);
void arch_teardown_dma_ops(struct device *dev)
{

View File

@ -399,6 +399,13 @@ void __iomem *ioremap_wc(resource_size_t res_cookie, size_t size)
}
EXPORT_SYMBOL(ioremap_wc);
void __iomem *ioremap_cache_ns(resource_size_t res_cookie, size_t size)
{
return arch_ioremap_caller(res_cookie, size, MT_MEMORY_RW_NS,
__builtin_return_address(0));
}
EXPORT_SYMBOL(ioremap_cache_ns);
/*
* Remap an arbitrary physical address space into the kernel virtual
* address space as memory. Needed when the kernel wants to execute

View File

@ -312,6 +312,13 @@ static struct mem_type mem_types[] __ro_after_init = {
.prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
.domain = DOMAIN_KERNEL,
},
[MT_MEMORY_RW_NS] = {
.prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
L_PTE_XN,
.prot_l1 = PMD_TYPE_TABLE,
.prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_XN,
.domain = DOMAIN_KERNEL,
},
[MT_ROM] = {
.prot_sect = PMD_TYPE_SECT,
.domain = DOMAIN_KERNEL,
@ -648,6 +655,7 @@ static void __init build_mem_type_table(void)
}
kern_pgprot |= PTE_EXT_AF;
vecs_pgprot |= PTE_EXT_AF;
mem_types[MT_MEMORY_RW_NS].prot_pte |= PTE_EXT_AF | cp->pte;
/*
* Set PXN for user mappings
@ -676,6 +684,7 @@ static void __init build_mem_type_table(void)
mem_types[MT_MEMORY_RWX].prot_pte |= kern_pgprot;
mem_types[MT_MEMORY_RW].prot_sect |= ecc_mask | cp->pmd;
mem_types[MT_MEMORY_RW].prot_pte |= kern_pgprot;
mem_types[MT_MEMORY_RW_NS].prot_sect |= ecc_mask | cp->pmd;
mem_types[MT_MEMORY_DMA_READY].prot_pte |= kern_pgprot;
mem_types[MT_MEMORY_RWX_NONCACHED].prot_sect |= ecc_mask;
mem_types[MT_ROM].prot_sect |= cp->pmd;

View File

@ -170,6 +170,7 @@ extern void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size);
#define ioremap_nocache(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
#define ioremap_wc(addr, size) __ioremap((addr), (size), __pgprot(PROT_NORMAL_NC))
#define ioremap_wt(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
#define ioremap_cache_ns(addr, size) __ioremap((addr), (size), __pgprot(PROT_NORMAL_NS))
/*
* PCI configuration space mapping function.

View File

@ -37,6 +37,7 @@
#define PROT_NORMAL_NC (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_NC))
#define PROT_NORMAL_WT (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_WT))
#define PROT_NORMAL (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL))
#define PROT_NORMAL_NS (PTE_TYPE_PAGE | PTE_AF | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL))
#define PROT_SECT_DEVICE_nGnRE (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_DEVICE_nGnRE))
#define PROT_SECT_NORMAL (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL))
@ -77,6 +78,7 @@
})
#define PAGE_S2 __pgprot(_PROT_DEFAULT | PAGE_S2_MEMATTR(NORMAL) | PTE_S2_RDONLY | PAGE_S2_XN)
#define PAGE_S2_NS __pgprot(PAGE_S2_MEMATTR(NORMAL) | PTE_S2_RDWR | PTE_TYPE_PAGE | PTE_AF)
#define PAGE_S2_DEVICE __pgprot(_PROT_DEFAULT | PAGE_S2_MEMATTR(DEVICE_nGnRE) | PTE_S2_RDONLY | PTE_S2_XN)
#define PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN)

View File

@ -418,6 +418,11 @@ static inline pmd_t pmd_mkdevmap(pmd_t pmd)
__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE) | PTE_PXN | PTE_UXN)
#define pgprot_writecombine(prot) \
__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN)
#define pgprot_cached(prot) \
__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL) | \
PTE_PXN | PTE_UXN)
#define pgprot_cached_ns(prot) \
__pgprot(pgprot_val(pgprot_cached(prot)) ^ PTE_SHARED)
#define pgprot_device(prot) \
__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_PXN | PTE_UXN)
/*

View File

@ -57,3 +57,4 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
dev->dma_ops = &xen_swiotlb_dma_ops;
#endif
}
EXPORT_SYMBOL(arch_setup_dma_ops);

View File

@ -322,7 +322,7 @@ config ARCH_HIBERNATION_POSSIBLE
config ARCH_SUSPEND_POSSIBLE
def_bool y
depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \
(PPC_85xx && !PPC_E500MC) || PPC_86xx || PPC_PSERIES \
FSL_SOC_BOOKE || PPC_86xx || PPC_PSERIES \
|| 44x || 40x
config ARCH_SUSPEND_NONZERO_CPU
@ -977,8 +977,6 @@ config FSL_PCI
config FSL_PMC
bool
default y
depends on SUSPEND && (PPC_85xx || PPC_86xx)
help
Freescale MPC85xx/MPC86xx power management controller support
(suspend/resume). For MPC83xx see platforms/83xx/suspend.c

View File

@ -42,6 +42,13 @@ extern void flush_dcache_page(struct page *page);
#define flush_dcache_mmap_lock(mapping) do { } while (0)
#define flush_dcache_mmap_unlock(mapping) do { } while (0)
extern void __flush_disable_L1(void);
#ifdef CONFIG_FSL_SOC_BOOKE
extern void flush_dcache_L1(void);
#else
#define flush_dcache_L1() do { } while (0)
#endif
extern void flush_icache_range(unsigned long, unsigned long);
extern void flush_icache_user_range(struct vm_area_struct *vma,
struct page *page, unsigned long addr,

View File

@ -43,6 +43,14 @@ extern int machine_check_e500mc(struct pt_regs *regs);
extern int machine_check_e500(struct pt_regs *regs);
extern int machine_check_e200(struct pt_regs *regs);
extern int machine_check_47x(struct pt_regs *regs);
#if defined(CONFIG_E500) || defined(CONFIG_PPC_E500MC)
extern void __flush_caches_e500v2(void);
extern void __flush_caches_e500mc(void);
extern void __flush_caches_e5500(void);
extern void __flush_caches_e6500(void);
#endif
int machine_check_8xx(struct pt_regs *regs);
int machine_check_83xx(struct pt_regs *regs);
@ -70,6 +78,10 @@ struct cpu_spec {
/* flush caches inside the current cpu */
void (*cpu_down_flush)(void);
#if defined(CONFIG_E500) || defined(CONFIG_PPC_E500MC)
/* flush caches of the cpu which is running the function */
void (*cpu_flush_caches)(void);
#endif
/* number of performance monitor counters */
unsigned int num_pmcs;
enum powerpc_pmc_type pmc_type;

View File

@ -7,6 +7,9 @@
#ifndef __PPC_FSL_PM_H
#define __PPC_FSL_PM_H
#ifndef __ASSEMBLY__
#include <linux/suspend.h>
#define E500_PM_PH10 1
#define E500_PM_PH15 2
#define E500_PM_PH20 3
@ -42,6 +45,34 @@ struct fsl_pm_ops {
extern const struct fsl_pm_ops *qoriq_pm_ops;
struct fsm_reg_vals {
u32 offset;
u32 value;
};
void fsl_fsm_setup(void __iomem *base, struct fsm_reg_vals *val);
void fsl_epu_setup_default(void __iomem *epu_base);
void fsl_npc_setup_default(void __iomem *npc_base);
void fsl_fsm_clean(void __iomem *base, struct fsm_reg_vals *val);
void fsl_epu_clean_default(void __iomem *epu_base);
extern int fsl_dp_iomap(void);
extern void fsl_dp_iounmap(void);
extern int fsl_enter_epu_deepsleep(void);
extern void fsl_dp_enter_low(void __iomem *ccsr_base, void __iomem *dcsr_base,
void __iomem *pld_base, int pld_flag);
extern void fsl_booke_deep_sleep_resume(void);
int __init fsl_rcpm_init(void);
void set_pm_suspend_state(suspend_state_t state);
suspend_state_t pm_suspend_state(void);
void fsl_set_power_except(struct device *dev, int on);
#endif /* __ASSEMBLY__ */
#define T1040QDS_TETRA_FLAG 1
#define T104xRDB_CPLD_FLAG 2
#endif /* __PPC_FSL_PM_H */

View File

@ -81,6 +81,7 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
ifneq ($(CONFIG_FA_DUMP)$(CONFIG_PRESERVE_FA_DUMP),)
obj-y += fadump.o
endif
obj-$(CONFIG_FSL_SOC) += fsl_pm.o
ifdef CONFIG_PPC32
obj-$(CONFIG_E500) += idle_e500.o
endif

View File

@ -365,6 +365,9 @@ int main(void)
OFFSET(CPU_SPEC_FEATURES, cpu_spec, cpu_features);
OFFSET(CPU_SPEC_SETUP, cpu_spec, cpu_setup);
OFFSET(CPU_SPEC_RESTORE, cpu_spec, cpu_restore);
#if defined(CONFIG_E500) || defined(CONFIG_PPC_E500MC)
OFFSET(CPU_FLUSH_CACHES, cpu_spec, cpu_flush_caches);
#endif
OFFSET(pbe_address, pbe, address);
OFFSET(pbe_orig_address, pbe, orig_address);

View File

@ -340,3 +340,84 @@ _GLOBAL(cpu_down_flush_e5500)
/* L1 Data Cache of e6500 contains no modified data, no flush is required */
_GLOBAL(cpu_down_flush_e6500)
blr
_GLOBAL(__flush_caches_e500v2)
mflr r0
bl flush_dcache_L1
mtlr r0
blr
_GLOBAL(__flush_caches_e500mc)
_GLOBAL(__flush_caches_e5500)
mflr r0
bl flush_dcache_L1
bl flush_backside_L2_cache
mtlr r0
blr
/* L1 Data Cache of e6500 contains no modified data, no flush is required */
_GLOBAL(__flush_caches_e6500)
blr
/* r3 = virtual address of L2 controller, WIMG = 01xx */
_GLOBAL(flush_disable_L2)
/* It's a write-through cache, so only invalidation is needed. */
mbar
isync
lwz r4, 0(r3)
li r5, 1
rlwimi r4, r5, 30, 0xc0000000
stw r4, 0(r3)
/* Wait for the invalidate to finish */
1: lwz r4, 0(r3)
andis. r4, r4, 0x4000
bne 1b
mbar
blr
/* r3 = virtual address of L2 controller, WIMG = 01xx */
_GLOBAL(invalidate_enable_L2)
mbar
isync
lwz r4, 0(r3)
li r5, 3
rlwimi r4, r5, 30, 0xc0000000
stw r4, 0(r3)
/* Wait for the invalidate to finish */
1: lwz r4, 0(r3)
andis. r4, r4, 0x4000
bne 1b
mbar
blr
/* Flush L1 d-cache, invalidate and disable d-cache and i-cache */
_GLOBAL(__flush_disable_L1)
mflr r10
bl flush_dcache_L1 /* Flush L1 d-cache */
mtlr r10
mfspr r4, SPRN_L1CSR0 /* Invalidate and disable d-cache */
li r5, 2
rlwimi r4, r5, 0, 3
msync
isync
mtspr SPRN_L1CSR0, r4
isync
1: mfspr r4, SPRN_L1CSR0 /* Wait for the invalidate to finish */
andi. r4, r4, 2
bne 1b
mfspr r4, SPRN_L1CSR1 /* Invalidate and disable i-cache */
li r5, 2
rlwimi r4, r5, 0, 3
mtspr SPRN_L1CSR1, r4
isync
blr

View File

@ -2051,6 +2051,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.machine_check = machine_check_e500,
.platform = "ppc8548",
.cpu_down_flush = cpu_down_flush_e500v2,
.cpu_flush_caches = __flush_caches_e500v2,
},
#else
{ /* e500mc */
@ -2071,6 +2072,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.machine_check = machine_check_e500mc,
.platform = "ppce500mc",
.cpu_down_flush = cpu_down_flush_e500mc,
.cpu_flush_caches = __flush_caches_e500mc,
},
#endif /* CONFIG_PPC_E500MC */
#endif /* CONFIG_PPC32 */
@ -2096,6 +2098,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.machine_check = machine_check_e500mc,
.platform = "ppce5500",
.cpu_down_flush = cpu_down_flush_e5500,
.cpu_flush_caches = __flush_caches_e5500,
},
{ /* e6500 */
.pvr_mask = 0xffff0000,
@ -2119,6 +2122,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.machine_check = machine_check_e500mc,
.platform = "ppce6500",
.cpu_down_flush = cpu_down_flush_e6500,
.cpu_flush_caches = __flush_caches_e6500,
},
#endif /* CONFIG_PPC_E500MC */
#ifdef CONFIG_PPC32

View File

@ -174,6 +174,10 @@ skpinv: addi r6,r6,1 /* Increment */
lis r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_NEEDED)@h
ori r6,r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_NEEDED)@l
mtspr SPRN_MAS2,r6
#ifdef ENTRY_DEEPSLEEP_SETUP
LOAD_REG_IMMEDIATE(r8, MEMORY_START)
ori r8,r8,(MAS3_SX|MAS3_SW|MAS3_SR)
#endif
mtspr SPRN_MAS3,r8
tlbwe
@ -216,12 +220,18 @@ next_tlb_setup:
#error You need to specify the mapping or not use this at all.
#endif
#ifdef ENTRY_DEEPSLEEP_SETUP
LOAD_REG_ADDR(r6, 2f)
mfmsr r7
rlwinm r7,r7,0,~(MSR_IS|MSR_DS)
#else
lis r7,MSR_KERNEL@h
ori r7,r7,MSR_KERNEL@l
bl 1f /* Find our address */
1: mflr r9
rlwimi r6,r9,0,20,31
addi r6,r6,(2f - 1b)
#endif
mtspr SPRN_SRR0,r6
mtspr SPRN_SRR1,r7
rfi /* start execution out of TLB1[0] entry */

View File

@ -0,0 +1,49 @@
/*
* Freescale General Power Management Implementation
*
* Copyright 2018 NXP
* Author: Wang Dongsheng <dongsheng.wang@freescale.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of the above-listed copyright holders nor the
* names of any contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") as published by the Free Software
* Foundation, either version 2 of that License or (at your option) any
* later version.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDERS 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/suspend.h>
#include <asm/fsl_pm.h>
static suspend_state_t pm_state;
void set_pm_suspend_state(suspend_state_t state)
{
pm_state = state;
}
suspend_state_t pm_suspend_state(void)
{
return pm_state;
}

View File

@ -860,7 +860,7 @@ _GLOBAL(start_secondary_resume)
/*
* This subroutine clobbers r11 and r12
*/
enable_64b_mode:
_GLOBAL(enable_64b_mode)
mfmsr r11 /* grab the current MSR */
#ifdef CONFIG_PPC_BOOK3E
oris r11,r11,0x8000 /* CM bit set, we'll set ICM later */

View File

@ -89,6 +89,12 @@ void print_system_hash_info(void);
#endif /* CONFIG_PPC_MMU_NOHASH */
void settlbcam(int index, unsigned long virt, phys_addr_t phys,
unsigned long size, unsigned long flags, unsigned int pid);
void cleartlbcam(unsigned long virt, unsigned int pid);
#ifdef CONFIG_PPC32
void hash_preload(struct mm_struct *mm, unsigned long ea);

View File

@ -102,7 +102,7 @@ unsigned long p_block_mapped(phys_addr_t pa)
* an unsigned long (for example, 32-bit implementations cannot support a 4GB
* size).
*/
static void settlbcam(int index, unsigned long virt, phys_addr_t phys,
void settlbcam(int index, unsigned long virt, phys_addr_t phys,
unsigned long size, unsigned long flags, unsigned int pid)
{
unsigned int tsize;
@ -140,6 +140,18 @@ static void settlbcam(int index, unsigned long virt, phys_addr_t phys,
tlbcam_addrs[index].phys = phys;
}
void cleartlbcam(unsigned long virt, unsigned int pid)
{
int i = 0;
for (i = 0; i < NUM_TLBCAMS; i++) {
if (tlbcam_addrs[i].start == virt) {
TLBCAM[i].MAS1 = 0;
loadcam_entry(i);
return;
}
}
}
unsigned long calc_cam_sz(unsigned long ram, unsigned long virt,
phys_addr_t phys)
{

View File

@ -34,7 +34,6 @@
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
#include <soc/fsl/qe/qe.h>
#include <soc/fsl/qe/qe_ic.h>
#include "mpc83xx.h"

View File

@ -14,7 +14,6 @@
#include <asm/io.h>
#include <asm/hw_irq.h>
#include <asm/ipic.h>
#include <soc/fsl/qe/qe_ic.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
@ -90,24 +89,9 @@ void __init mpc83xx_ipic_init_IRQ(void)
}
#ifdef CONFIG_QUICC_ENGINE
void __init mpc83xx_qe_init_IRQ(void)
{
struct device_node *np;
np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
if (!np) {
np = of_find_node_by_type(NULL, "qeic");
if (!np)
return;
}
qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic);
of_node_put(np);
}
void __init mpc83xx_ipic_and_qe_init_IRQ(void)
{
mpc83xx_ipic_init_IRQ();
mpc83xx_qe_init_IRQ();
}
#endif /* CONFIG_QUICC_ENGINE */

View File

@ -33,7 +33,6 @@
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
#include <soc/fsl/qe/qe.h>
#include <soc/fsl/qe/qe_ic.h>
#include "mpc83xx.h"

View File

@ -22,7 +22,6 @@
#include <asm/ipic.h>
#include <asm/udbg.h>
#include <soc/fsl/qe/qe.h>
#include <soc/fsl/qe/qe_ic.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>

View File

@ -41,7 +41,6 @@
#include <sysdev/fsl_pci.h>
#include <sysdev/simple_gpio.h>
#include <soc/fsl/qe/qe.h>
#include <soc/fsl/qe/qe_ic.h>
#include "mpc83xx.h"

View File

@ -17,7 +17,6 @@
#include <asm/ipic.h>
#include <asm/udbg.h>
#include <soc/fsl/qe/qe.h>
#include <soc/fsl/qe/qe_ic.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>

View File

@ -10,6 +10,8 @@ menuconfig FSL_SOC_BOOKE
select SERIAL_8250_EXTENDED if SERIAL_8250
select SERIAL_8250_SHARE_IRQ if SERIAL_8250
select FSL_CORENET_RCPM if PPC_E500MC
select FSL_QORIQ_PM if SUSPEND && PPC_E500MC
select FSL_PMC if SUSPEND && !PPC_E500MC
default y
if FSL_SOC_BOOKE
@ -292,3 +294,7 @@ endif # FSL_SOC_BOOKE
config TQM85xx
bool
config FSL_QORIQ_PM
bool
select FSL_SLEEP_FSM

View File

@ -3,7 +3,9 @@
# Makefile for the PowerPC 85xx linux kernel.
#
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_SUSPEND) += sleep.o
obj-$(CONFIG_FSL_PMC) += mpc85xx_pm_ops.o
obj-$(CONFIG_FSL_QORIQ_PM) += qoriq_pm.o deepsleep.o
obj-y += common.o

View File

@ -24,7 +24,6 @@
#include <asm/mpic.h>
#include <asm/ehv_pic.h>
#include <asm/swiotlb.h>
#include <soc/fsl/qe/qe_ic.h>
#include <linux/of_platform.h>
#include <sysdev/fsl_soc.h>
@ -38,8 +37,6 @@ void __init corenet_gen_pic_init(void)
unsigned int flags = MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU |
MPIC_NO_RESET;
struct device_node *np;
if (ppc_md.get_irq == mpic_get_coreint_irq)
flags |= MPIC_ENABLE_COREINT;
@ -47,13 +44,6 @@ void __init corenet_gen_pic_init(void)
BUG_ON(mpic == NULL);
mpic_init(mpic);
np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
if (np) {
qe_ic_init(np, 0, qe_ic_cascade_low_mpic,
qe_ic_cascade_high_mpic);
of_node_put(np);
}
}
/*

View File

@ -0,0 +1,349 @@
/*
* Support deep sleep feature for T104x
*
* Copyright 2018 NXP
* Author: Chenhui Zhao <chenhui.zhao@freescale.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of the above-listed copyright holders nor the
* names of any contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") as published by the Free Software
* Foundation, either version 2 of that License or (at your option) any
* later version.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDERS 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/kernel.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/slab.h>
#include <sysdev/fsl_soc.h>
#include <asm/machdep.h>
#include <asm/fsl_pm.h>
#define SIZE_1MB 0x100000
#define SIZE_2MB 0x200000
#define CPC_CPCHDBCR0 0x10f00
#define CPC_CPCHDBCR0_SPEC_DIS 0x08000000
#define CCSR_SCFG_DPSLPCR 0xfc000
#define CCSR_SCFG_DPSLPCR_WDRR_EN 0x1
#define CCSR_SCFG_SPARECR2 0xfc504
#define CCSR_SCFG_SPARECR3 0xfc508
#define CCSR_GPIO1_GPDIR 0x130000
#define CCSR_GPIO1_GPODR 0x130004
#define CCSR_GPIO1_GPDAT 0x130008
#define CCSR_GPIO1_GPDIR_29 0x4
#define RCPM_BLOCK_OFFSET 0x00022000
#define EPU_BLOCK_OFFSET 0x00000000
#define NPC_BLOCK_OFFSET 0x00001000
#define CSTTACR0 0xb00
#define CG1CR0 0x31c
#define CCSR_LAW_BASE 0xC00
#define DCFG_BRR 0xE4 /* boot release register */
#define LCC_BSTRH 0x20 /* Boot space translation register high */
#define LCC_BSTRL 0x24 /* Boot space translation register low */
#define LCC_BSTAR 0x28 /* Boot space translation attribute register */
#define RCPM_PCTBENR 0x1A0 /* Physical Core Timebase Enable Register */
#define RCPM_BASE 0xE2000
#define DCFG_BASE 0xE0000
/* 128 bytes buffer for restoring data broke by DDR training initialization */
#define DDR_BUF_SIZE 128
static u8 ddr_buff[DDR_BUF_SIZE] __aligned(64);
static void *dcsr_base, *ccsr_base, *pld_base;
static int pld_flag;
/* for law */
struct fsl_law {
u32 lawbarh; /* LAWn base address high */
u32 lawbarl; /* LAWn base address low */
u32 lawar; /* LAWn attributes */
u32 reserved;
};
struct fsl_law *saved_law;
static u32 num_laws;
/* for nonboot cpu */
struct fsl_bstr {
u32 bstrh;
u32 bstrl;
u32 bstar;
u32 cpu_mask;
};
static struct fsl_bstr saved_bstr;
int fsl_dp_iomap(void)
{
struct device_node *np;
int ret = 0;
phys_addr_t ccsr_phy_addr, dcsr_phy_addr;
saved_law = NULL;
ccsr_base = NULL;
dcsr_base = NULL;
pld_base = NULL;
ccsr_phy_addr = get_immrbase();
if (ccsr_phy_addr == -1) {
pr_err("%s: Can't get the address of CCSR\n", __func__);
ret = -EINVAL;
goto ccsr_err;
}
ccsr_base = ioremap(ccsr_phy_addr, SIZE_2MB);
if (!ccsr_base) {
ret = -ENOMEM;
goto ccsr_err;
}
dcsr_phy_addr = get_dcsrbase();
if (dcsr_phy_addr == -1) {
pr_err("%s: Can't get the address of DCSR\n", __func__);
ret = -EINVAL;
goto dcsr_err;
}
dcsr_base = ioremap(dcsr_phy_addr, SIZE_1MB);
if (!dcsr_base) {
ret = -ENOMEM;
goto dcsr_err;
}
np = of_find_compatible_node(NULL, NULL, "fsl,tetra-fpga");
if (np) {
pld_flag = T1040QDS_TETRA_FLAG;
} else {
np = of_find_compatible_node(NULL, NULL, "fsl,deepsleep-cpld");
if (np) {
pld_flag = T104xRDB_CPLD_FLAG;
} else {
pr_err("%s: Can't find the FPGA/CPLD node\n",
__func__);
ret = -EINVAL;
goto pld_err;
}
}
pld_base = of_iomap(np, 0);
of_node_put(np);
np = of_find_compatible_node(NULL, NULL, "fsl,corenet-law");
if (!np) {
pr_err("%s: Can't find the node of \"law\"\n", __func__);
ret = -EINVAL;
goto alloc_err;
}
ret = of_property_read_u32(np, "fsl,num-laws", &num_laws);
if (ret) {
ret = -EINVAL;
goto alloc_err;
}
saved_law = kzalloc(sizeof(*saved_law) * num_laws, GFP_KERNEL);
if (!saved_law) {
ret = -ENOMEM;
goto alloc_err;
}
of_node_put(np);
return 0;
alloc_err:
iounmap(pld_base);
pld_base = NULL;
pld_err:
iounmap(dcsr_base);
dcsr_base = NULL;
dcsr_err:
iounmap(ccsr_base);
ccsr_base = NULL;
ccsr_err:
return ret;
}
void fsl_dp_iounmap(void)
{
if (dcsr_base) {
iounmap(dcsr_base);
dcsr_base = NULL;
}
if (ccsr_base) {
iounmap(ccsr_base);
ccsr_base = NULL;
}
if (pld_base) {
iounmap(pld_base);
pld_base = NULL;
}
kfree(saved_law);
saved_law = NULL;
}
static void fsl_dp_ddr_save(void *ccsr_base)
{
u32 ddr_buff_addr;
/*
* DDR training initialization will break 128 bytes at the beginning
* of DDR, therefore, save them so that the bootloader will restore
* them. Assume that DDR is mapped to the address space started with
* CONFIG_PAGE_OFFSET.
*/
memcpy(ddr_buff, (void *)CONFIG_PAGE_OFFSET, DDR_BUF_SIZE);
/* assume ddr_buff is in the physical address space of 4GB */
ddr_buff_addr = (u32)(__pa(ddr_buff) & 0xffffffff);
/*
* the bootloader will restore the first 128 bytes of DDR from
* the location indicated by the register SPARECR3
*/
out_be32(ccsr_base + CCSR_SCFG_SPARECR3, ddr_buff_addr);
}
static void fsl_dp_mp_save(void *ccsr)
{
struct fsl_bstr *dst = &saved_bstr;
dst->bstrh = in_be32(ccsr + LCC_BSTRH);
dst->bstrl = in_be32(ccsr + LCC_BSTRL);
dst->bstar = in_be32(ccsr + LCC_BSTAR);
dst->cpu_mask = in_be32(ccsr + DCFG_BASE + DCFG_BRR);
}
static void fsl_dp_mp_restore(void *ccsr)
{
struct fsl_bstr *src = &saved_bstr;
out_be32(ccsr + LCC_BSTRH, src->bstrh);
out_be32(ccsr + LCC_BSTRL, src->bstrl);
out_be32(ccsr + LCC_BSTAR, src->bstar);
/* release the nonboot cpus */
out_be32(ccsr + DCFG_BASE + DCFG_BRR, src->cpu_mask);
/* enable the time base */
out_be32(ccsr + RCPM_BASE + RCPM_PCTBENR, src->cpu_mask);
/* read back to sync write */
in_be32(ccsr + RCPM_BASE + RCPM_PCTBENR);
}
static void fsl_dp_law_save(void *ccsr)
{
int i;
struct fsl_law *dst = saved_law;
struct fsl_law *src = (void *)(ccsr + CCSR_LAW_BASE);
for (i = 0; i < num_laws; i++) {
dst->lawbarh = in_be32(&src->lawbarh);
dst->lawbarl = in_be32(&src->lawbarl);
dst->lawar = in_be32(&src->lawar);
dst++;
src++;
}
}
static void fsl_dp_law_restore(void *ccsr)
{
int i;
struct fsl_law *src = saved_law;
struct fsl_law *dst = (void *)(ccsr + CCSR_LAW_BASE);
for (i = 0; i < num_laws - 1; i++) {
out_be32(&dst->lawar, 0);
out_be32(&dst->lawbarl, src->lawbarl);
out_be32(&dst->lawbarh, src->lawbarh);
out_be32(&dst->lawar, src->lawar);
/* Read back so that we sync the writes */
in_be32(&dst->lawar);
src++;
dst++;
}
}
static void fsl_dp_set_resume_pointer(void *ccsr_base)
{
u32 resume_addr;
/* the bootloader will finally jump to this address to return kernel */
#ifdef CONFIG_PPC32
resume_addr = (u32)(__pa(fsl_booke_deep_sleep_resume));
#else
resume_addr = (u32)(__pa(*(u64 *)fsl_booke_deep_sleep_resume)
& 0xffffffff);
#endif
/* use the register SPARECR2 to save the resume address */
out_be32(ccsr_base + CCSR_SCFG_SPARECR2, resume_addr);
}
int fsl_enter_epu_deepsleep(void)
{
fsl_dp_ddr_save(ccsr_base);
fsl_dp_set_resume_pointer(ccsr_base);
fsl_dp_mp_save(ccsr_base);
fsl_dp_law_save(ccsr_base);
/* enable Warm Device Reset request. */
setbits32(ccsr_base + CCSR_SCFG_DPSLPCR, CCSR_SCFG_DPSLPCR_WDRR_EN);
/* set GPIO1_29 as an output pin (not open-drain), and output 0 */
clrbits32(ccsr_base + CCSR_GPIO1_GPDAT, CCSR_GPIO1_GPDIR_29);
clrbits32(ccsr_base + CCSR_GPIO1_GPODR, CCSR_GPIO1_GPDIR_29);
setbits32(ccsr_base + CCSR_GPIO1_GPDIR, CCSR_GPIO1_GPDIR_29);
/*
* Disable CPC speculation to avoid deep sleep hang, especially
* in secure boot mode. This bit will be cleared automatically
* when resuming from deep sleep.
*/
setbits32(ccsr_base + CPC_CPCHDBCR0, CPC_CPCHDBCR0_SPEC_DIS);
fsl_epu_setup_default(dcsr_base + EPU_BLOCK_OFFSET);
fsl_npc_setup_default(dcsr_base + NPC_BLOCK_OFFSET);
out_be32(dcsr_base + RCPM_BLOCK_OFFSET + CSTTACR0, 0x00001001);
out_be32(dcsr_base + RCPM_BLOCK_OFFSET + CG1CR0, 0x00000001);
fsl_dp_enter_low(ccsr_base, dcsr_base, pld_base, pld_flag);
fsl_dp_law_restore(ccsr_base);
fsl_dp_mp_restore(ccsr_base);
/* disable Warm Device Reset request */
clrbits32(ccsr_base + CCSR_SCFG_DPSLPCR, CCSR_SCFG_DPSLPCR_WDRR_EN);
fsl_epu_clean_default(dcsr_base + EPU_BLOCK_OFFSET);
return 0;
}

View File

@ -45,7 +45,6 @@
#include <sysdev/fsl_pci.h>
#include <sysdev/simple_gpio.h>
#include <soc/fsl/qe/qe.h>
#include <soc/fsl/qe/qe_ic.h>
#include <asm/mpic.h>
#include <asm/swiotlb.h>
#include "smp.h"
@ -279,20 +278,6 @@ static void __init mpc85xx_mds_qeic_init(void)
of_node_put(np);
return;
}
np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
if (!np) {
np = of_find_node_by_type(NULL, "qeic");
if (!np)
return;
}
if (machine_is(p1021_mds))
qe_ic_init(np, 0, qe_ic_cascade_low_mpic,
qe_ic_cascade_high_mpic);
else
qe_ic_init(np, 0, qe_ic_cascade_muxed_mpic, NULL);
of_node_put(np);
}
#else
static void __init mpc85xx_mds_qe_init(void) { }

View File

@ -23,7 +23,6 @@
#include <asm/udbg.h>
#include <asm/mpic.h>
#include <soc/fsl/qe/qe.h>
#include <soc/fsl/qe/qe_ic.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
@ -44,10 +43,6 @@ void __init mpc85xx_rdb_pic_init(void)
{
struct mpic *mpic;
#ifdef CONFIG_QUICC_ENGINE
struct device_node *np;
#endif
if (of_machine_is_compatible("fsl,MPC85XXRDB-CAMP")) {
mpic = mpic_alloc(NULL, 0, MPIC_NO_RESET |
MPIC_BIG_ENDIAN |
@ -62,18 +57,6 @@ void __init mpc85xx_rdb_pic_init(void)
BUG_ON(mpic == NULL);
mpic_init(mpic);
#ifdef CONFIG_QUICC_ENGINE
np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
if (np) {
qe_ic_init(np, 0, qe_ic_cascade_low_mpic,
qe_ic_cascade_high_mpic);
of_node_put(np);
} else
pr_err("%s: Could not find qe-ic node\n", __func__);
#endif
}
/*

View File

@ -0,0 +1,222 @@
/*
* Support Power Management feature
*
* Copyright 2018 NXP
* Author: Chenhui Zhao <chenhui.zhao@freescale.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of the above-listed copyright holders nor the
* names of any contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") as published by the Free Software
* Foundation, either version 2 of that License or (at your option) any
* later version.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDERS 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/kernel.h>
#include <linux/suspend.h>
#include <linux/of_platform.h>
#include <linux/usb.h>
#include <asm/fsl_pm.h>
#define FSL_SLEEP 0x1
#define FSL_DEEP_SLEEP 0x2
int (*fsl_enter_deepsleep)(void);
/* specify the sleep state of the present platform */
unsigned int sleep_pm_state;
/* supported sleep modes by the present platform */
static unsigned int sleep_modes;
/**
* fsl_set_power_except - set which IP block is not powerdown when sleep,
* such as MAC, USB, etc.
*
* @dev: a pointer to the struct device
* @on: if 1, do not power down; if 0, power down.
*/
void fsl_set_power_except(struct device *dev, int on)
{
u32 value[2];
u32 pw_mask;
int ret;
struct device_node *mac_node;
const phandle *phandle_prop;
if (dev && !strncmp(dev->bus->name, "usb", 3)) {
struct usb_device *udev = container_of(dev,
struct usb_device, dev);
struct device *controller = udev->bus->controller;
ret = of_property_read_u32_array(controller->parent->of_node,
"sleep", value, 2);
} else
ret = of_property_read_u32_array(dev->of_node, "sleep",
value, 2);
if (ret) {
/* search fman mac node */
phandle_prop = of_get_property(dev->of_node, "fsl,fman-mac",
NULL);
if (phandle_prop == NULL)
goto err;
mac_node = of_find_node_by_phandle(*phandle_prop);
ret = of_property_read_u32_array(mac_node, "sleep", value, 2);
of_node_put(mac_node);
if (ret)
goto err;
}
/* get the second value, it is a mask */
pw_mask = value[1];
qoriq_pm_ops->set_ip_power(on, pw_mask);
return;
err:
dev_err(dev, "Can not set wakeup sources\n");
}
EXPORT_SYMBOL_GPL(fsl_set_power_except);
void qoriq_set_wakeup_source(struct device *dev, void *enable)
{
if (!device_may_wakeup(dev))
return;
fsl_set_power_except(dev, *((int *)enable));
}
static int qoriq_suspend_enter(suspend_state_t state)
{
int ret = 0;
int cpu;
switch (state) {
case PM_SUSPEND_STANDBY:
if (cur_cpu_spec->cpu_flush_caches)
cur_cpu_spec->cpu_flush_caches();
ret = qoriq_pm_ops->plat_enter_sleep();
break;
case PM_SUSPEND_MEM:
cpu = smp_processor_id();
qoriq_pm_ops->irq_mask(cpu);
ret = fsl_enter_deepsleep();
qoriq_pm_ops->irq_unmask(cpu);
break;
default:
ret = -EINVAL;
}
return ret;
}
static int qoriq_suspend_valid(suspend_state_t state)
{
set_pm_suspend_state(state);
if (state == PM_SUSPEND_STANDBY && (sleep_modes & FSL_SLEEP))
return 1;
if (state == PM_SUSPEND_MEM && (sleep_modes & FSL_DEEP_SLEEP))
return 1;
set_pm_suspend_state(PM_SUSPEND_ON);
return 0;
}
static int qoriq_suspend_begin(suspend_state_t state)
{
const int enable = 1;
dpm_for_each_dev((void *)&enable, qoriq_set_wakeup_source);
if (state == PM_SUSPEND_MEM)
return fsl_dp_iomap();
return 0;
}
static void qoriq_suspend_end(void)
{
const int enable = 0;
dpm_for_each_dev((void *)&enable, qoriq_set_wakeup_source);
set_pm_suspend_state(PM_SUSPEND_ON);
fsl_dp_iounmap();
}
static const struct platform_suspend_ops qoriq_suspend_ops = {
.valid = qoriq_suspend_valid,
.enter = qoriq_suspend_enter,
.begin = qoriq_suspend_begin,
.end = qoriq_suspend_end,
};
static const struct of_device_id deepsleep_matches[] = {
{
.compatible = "fsl,t1040-rcpm",
},
{
.compatible = "fsl,t1024-rcpm",
},
{
.compatible = "fsl,t1023-rcpm",
},
{},
};
static int __init qoriq_suspend_init(void)
{
struct device_node *np;
sleep_modes = FSL_SLEEP;
sleep_pm_state = PLAT_PM_SLEEP;
np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-rcpm-2.0");
if (np)
sleep_pm_state = PLAT_PM_LPM20;
np = of_find_matching_node_and_match(NULL, deepsleep_matches, NULL);
if (np) {
fsl_enter_deepsleep = fsl_enter_epu_deepsleep;
sleep_modes |= FSL_DEEP_SLEEP;
}
suspend_set_ops(&qoriq_suspend_ops);
set_pm_suspend_state(PM_SUSPEND_ON);
return 0;
}
arch_initcall(qoriq_suspend_init);

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,6 @@
#include <asm/udbg.h>
#include <asm/mpic.h>
#include <soc/fsl/qe/qe.h>
#include <soc/fsl/qe/qe_ic.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
@ -31,26 +30,12 @@ static void __init twr_p1025_pic_init(void)
{
struct mpic *mpic;
#ifdef CONFIG_QUICC_ENGINE
struct device_node *np;
#endif
mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
MPIC_SINGLE_DEST_CPU,
0, 256, " OpenPIC ");
BUG_ON(mpic == NULL);
mpic_init(mpic);
#ifdef CONFIG_QUICC_ENGINE
np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
if (np) {
qe_ic_init(np, 0, qe_ic_cascade_low_mpic,
qe_ic_cascade_high_mpic);
of_node_put(np);
} else
pr_err("Could not find qe-ic node\n");
#endif
}
/* ************************************************************************

View File

@ -5,6 +5,7 @@ menuconfig PPC_86xx
depends on PPC_BOOK3S_32
select FSL_SOC
select ALTIVEC
select FSL_PMC if SUSPEND
help
The Freescale E600 SoCs have 74xx cores.

View File

@ -16,54 +16,192 @@
#include <linux/device.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/pm.h>
#include <asm/cacheflush.h>
#include <sysdev/fsl_soc.h>
#include <asm/switch_to.h>
#include <asm/fsl_pm.h>
struct pmc_regs {
__be32 devdisr;
__be32 devdisr2;
__be32 :32;
__be32 :32;
__be32 pmcsr;
#define PMCSR_SLP (1 << 17)
__be32 res1;
__be32 res2;
__be32 powmgtcsr;
#define POWMGTCSR_SLP 0x00020000
#define POWMGTCSR_DPSLP 0x00100000
#define POWMGTCSR_LOSSLESS 0x00400000
__be32 res3[2];
__be32 pmcdr;
};
static struct device *pmc_dev;
static struct pmc_regs __iomem *pmc_regs;
static unsigned int pmc_flag;
#define PMC_SLEEP 0x1
#define PMC_DEEP_SLEEP 0x2
#define PMC_LOSSLESS 0x4
/**
* mpc85xx_pmc_set_wake - enable devices as wakeup event source
* @dev: a device affected
* @enable: True to enable event generation; false to disable
*
* This enables the device as a wakeup event source, or disables it.
*
* RETURN VALUE:
* 0 is returned on success.
* -EINVAL is returned if device is not supposed to wake up the system.
* -ENODEV is returned if PMC is unavailable.
* Error code depending on the platform is returned if both the platform and
* the native mechanism fail to enable the generation of wake-up events
*/
int mpc85xx_pmc_set_wake(struct device *dev, bool enable)
{
int ret = 0;
struct device_node *clk_np;
const u32 *prop;
u32 pmcdr_mask;
if (!pmc_regs) {
dev_err(dev, "%s: PMC is unavailable\n", __func__);
return -ENODEV;
}
if (enable && !device_may_wakeup(dev))
return -EINVAL;
clk_np = of_parse_phandle(dev->of_node, "fsl,pmc-handle", 0);
if (!clk_np)
return -EINVAL;
prop = of_get_property(clk_np, "fsl,pmcdr-mask", NULL);
if (!prop) {
ret = -EINVAL;
goto out;
}
pmcdr_mask = be32_to_cpup(prop);
if (enable)
/* clear to enable clock in low power mode */
clrbits32(&pmc_regs->pmcdr, pmcdr_mask);
else
setbits32(&pmc_regs->pmcdr, pmcdr_mask);
out:
of_node_put(clk_np);
return ret;
}
EXPORT_SYMBOL_GPL(mpc85xx_pmc_set_wake);
/**
* mpc85xx_pmc_set_lossless_ethernet - enable lossless ethernet
* in (deep) sleep mode
* @enable: True to enable event generation; false to disable
*/
void mpc85xx_pmc_set_lossless_ethernet(int enable)
{
if (pmc_flag & PMC_LOSSLESS) {
if (enable)
setbits32(&pmc_regs->powmgtcsr, POWMGTCSR_LOSSLESS);
else
clrbits32(&pmc_regs->powmgtcsr, POWMGTCSR_LOSSLESS);
}
}
EXPORT_SYMBOL_GPL(mpc85xx_pmc_set_lossless_ethernet);
static int pmc_suspend_enter(suspend_state_t state)
{
int ret;
int ret = 0;
int result;
setbits32(&pmc_regs->pmcsr, PMCSR_SLP);
/* At this point, the CPU is asleep. */
switch (state) {
#ifdef CONFIG_PPC_85xx
case PM_SUSPEND_MEM:
#ifdef CONFIG_SPE
enable_kernel_spe();
#endif
#ifdef CONFIG_PPC_FPU
enable_kernel_fp();
#endif
/* Upon resume, wait for SLP bit to be clear. */
ret = spin_event_timeout((in_be32(&pmc_regs->pmcsr) & PMCSR_SLP) == 0,
10000, 10) ? 0 : -ETIMEDOUT;
if (ret)
dev_err(pmc_dev, "tired waiting for SLP bit to clear\n");
pr_debug("%s: Entering deep sleep\n", __func__);
local_irq_disable();
mpc85xx_enter_deep_sleep(get_immrbase(), POWMGTCSR_DPSLP);
pr_debug("%s: Resumed from deep sleep\n", __func__);
break;
#endif
case PM_SUSPEND_STANDBY:
local_irq_disable();
flush_dcache_L1();
setbits32(&pmc_regs->powmgtcsr, POWMGTCSR_SLP);
/* At this point, the CPU is asleep. */
/* Upon resume, wait for SLP bit to be clear. */
result = spin_event_timeout(
(in_be32(&pmc_regs->powmgtcsr) & POWMGTCSR_SLP) == 0,
10000, 10);
if (!result) {
pr_err("%s: timeout waiting for SLP bit "
"to be cleared\n", __func__);
ret = -ETIMEDOUT;
}
break;
default:
ret = -EINVAL;
}
return ret;
}
static int pmc_suspend_valid(suspend_state_t state)
{
if (state != PM_SUSPEND_STANDBY)
return 0;
return 1;
set_pm_suspend_state(state);
if (((pmc_flag & PMC_SLEEP) && (state == PM_SUSPEND_STANDBY)) ||
((pmc_flag & PMC_DEEP_SLEEP) && (state == PM_SUSPEND_MEM)))
return 1;
set_pm_suspend_state(PM_SUSPEND_ON);
return 0;
}
static void pmc_suspend_end(void)
{
set_pm_suspend_state(PM_SUSPEND_ON);
}
static const struct platform_suspend_ops pmc_suspend_ops = {
.valid = pmc_suspend_valid,
.enter = pmc_suspend_enter,
.end = pmc_suspend_end,
};
static int pmc_probe(struct platform_device *ofdev)
static int pmc_probe(struct platform_device *pdev)
{
pmc_regs = of_iomap(ofdev->dev.of_node, 0);
struct device_node *np = pdev->dev.of_node;
pmc_regs = of_iomap(np, 0);
if (!pmc_regs)
return -ENOMEM;
pmc_dev = &ofdev->dev;
pmc_flag = PMC_SLEEP;
if (of_device_is_compatible(np, "fsl,mpc8536-pmc"))
pmc_flag |= PMC_DEEP_SLEEP;
if (of_device_is_compatible(np, "fsl,p1022-pmc"))
pmc_flag |= PMC_DEEP_SLEEP | PMC_LOSSLESS;
suspend_set_ops(&pmc_suspend_ops);
set_pm_suspend_state(PM_SUSPEND_ON);
pr_info("Freescale PMC driver\n");
return 0;
}

View File

@ -42,6 +42,37 @@ extern void init_fcc_ioports(struct fs_platform_info*);
extern void init_fec_ioports(struct fs_platform_info*);
extern void init_smc_ioports(struct fs_uart_platform_info*);
static phys_addr_t immrbase = -1;
static phys_addr_t dcsrbase = -1;
phys_addr_t get_dcsrbase(void)
{
struct device_node *np;
const __be32 *prop;
int size;
u32 naddr;
if (dcsrbase != -1)
return dcsrbase;
np = of_find_compatible_node(NULL, NULL, "fsl,dcsr");
if (!np)
return -1;
prop = of_get_property(np, "#address-cells", &size);
if (prop && size == 4)
naddr = be32_to_cpup(prop);
else
naddr = 2;
prop = of_get_property(np, "ranges", NULL);
if (prop)
dcsrbase = of_translate_address(np, prop + naddr);
of_node_put(np);
return dcsrbase;
}
EXPORT_SYMBOL(get_dcsrbase);
phys_addr_t get_immrbase(void)
{

View File

@ -7,6 +7,7 @@
struct spi_device;
extern phys_addr_t get_dcsrbase(void);
extern phys_addr_t get_immrbase(void);
#if defined(CONFIG_CPM) || defined(CONFIG_QUICC_ENGINE)
extern u32 get_brgfreq(void);
@ -44,5 +45,22 @@ extern struct platform_diu_data_ops diu_ops;
void __noreturn fsl_hv_restart(char *cmd);
void __noreturn fsl_hv_halt(void);
/*
* Cast the ccsrbar to 64-bit parameter so that the assembly
* code can be compatible with both 32-bit & 36-bit.
*/
extern void mpc85xx_enter_deep_sleep(u64 ccsrbar, u32 powmgtreq);
#ifdef CONFIG_FSL_PMC
int mpc85xx_pmc_set_wake(struct device *dev, bool enable);
void mpc85xx_pmc_set_lossless_ethernet(int enable);
#else
static inline int mpc85xx_pmc_set_wake(struct device *dev, bool enable)
{
return -ENODEV;
}
#define mpc85xx_pmc_set_lossless_ethernet(enable) do { } while (0)
#endif
#endif
#endif

View File

@ -40,4 +40,15 @@ config DPAA2_CONSOLE
/dev/dpaa2_mc_console and /dev/dpaa2_aiop_console,
which can be used to dump the Management Complex and AIOP
firmware logs.
config FSL_QIXIS
tristate "QIXIS system controller driver"
depends on OF
select REGMAP_I2C
select REGMAP_MMIO
default n
help
Say y here to enable QIXIS system controller api. The qixis driver
provides FPGA functions to control system.
endmenu

View File

@ -6,6 +6,7 @@
obj-$(CONFIG_FSL_DPAA) += qbman/
obj-$(CONFIG_QUICC_ENGINE) += qe/
obj-$(CONFIG_CPM) += qe/
obj-$(CONFIG_FSL_QIXIS) += qixis_ctrl.o
obj-$(CONFIG_FSL_GUTS) += guts.o
obj-$(CONFIG_FSL_MC_DPIO) += dpio/
obj-$(CONFIG_DPAA2_CONSOLE) += dpaa2-console.o

View File

@ -0,0 +1,105 @@
// SPDX-License-Identifier: GPL-2.0+
/* Freescale QIXIS system controller driver.
*
* Copyright 2015 Freescale Semiconductor, Inc.
* Copyright 2018-2019 NXP
*/
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/mfd/core.h>
#include <linux/of.h>
#include <linux/regmap.h>
/* QIXIS MAP */
struct fsl_qixis_regs {
u8 id; /* Identification Registers */
u8 version; /* Version Register */
u8 qixis_ver; /* QIXIS Version Register */
u8 reserved1[0x1f];
};
struct qixis_priv {
struct regmap *regmap;
};
static struct regmap_config qixis_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
static const struct mfd_cell fsl_qixis_devs[] = {
{
.name = "reg-mux",
.of_compatible = "reg-mux",
},
};
static int fsl_qixis_i2c_probe(struct i2c_client *client)
{
struct qixis_priv *priv;
int ret = 0;
u32 qver;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EOPNOTSUPP;
priv = devm_kzalloc(&client->dev, sizeof(struct qixis_priv),
GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->regmap = regmap_init_i2c(client, &qixis_regmap_config);
regmap_read(priv->regmap, offsetof(struct fsl_qixis_regs, qixis_ver),
&qver);
pr_info("Freescale QIXIS Version: 0x%08x\n", qver);
i2c_set_clientdata(client, priv);
if (of_device_is_compatible(client->dev.of_node, "simple-mfd"))
ret = devm_mfd_add_devices(&client->dev, -1, fsl_qixis_devs,
ARRAY_SIZE(fsl_qixis_devs), NULL, 0,
NULL);
if (ret)
goto error;
return ret;
error:
regmap_exit(priv->regmap);
return ret;
}
static int fsl_qixis_i2c_remove(struct i2c_client *client)
{
struct qixis_priv *priv;
priv = i2c_get_clientdata(client);
regmap_exit(priv->regmap);
return 0;
}
static const struct of_device_id fsl_qixis_i2c_of_match[] = {
{ .compatible = "fsl,fpga-qixis-i2c" },
{}
};
MODULE_DEVICE_TABLE(of, fsl_qixis_i2c_of_match);
static struct i2c_driver fsl_qixis_i2c_driver = {
.driver = {
.name = "qixis_ctrl_i2c",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(fsl_qixis_i2c_of_match),
},
.probe_new = fsl_qixis_i2c_probe,
.remove = fsl_qixis_i2c_remove,
};
module_i2c_driver(fsl_qixis_i2c_driver);
MODULE_AUTHOR("Wang Dongsheng <dongsheng.wang@freescale.com>");
MODULE_DESCRIPTION("Freescale QIXIS system controller driver");
MODULE_LICENSE("GPL");