mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 18:51:56 -04:00
ARM: SoC platform updates for v4.4
New and/or improved SoC support for this release:
- Marvell Berlin:
* Enable standard DT-based cpufreq
* Add CPU hotplug support
- Freescale:
* Ethernet init for i.MX7D
* Suspend/resume support for i.MX6UL
- Allwinner:
* Support for R8 chipset (used on NTC's $9 C.H.I.P board)
- Mediatek:
* SMP support for some platforms
- Uniphier:
* L2 support
* Cleaned up SMP support, etc.
+ A handful of other patches around above functionality, and a few other
smaller changes.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQIcBAABAgAGBQJWQCmaAAoJEIwa5zzehBx3F/0QAKIYmvmJM3sUanNEEwhRilx+
3xhSgld7e25suLGwrNapTkd8VzVB4b8GnJhNShNk+l5WqfqICHCB4Aru2NmJHY8V
yPj5vBrgJTVMnIiH7CRDPz9IlwAkWM4MmWi4PgFuhrk1T/0wPKPNMc40OWOloTeD
gA5YmbbX1hNOqKoI/z+DK7CEdp1lHrEjeYIbnQ0SldFzkY9NKhrI784gtcz3si6E
19pFQ9LA7EtEv7aRcFOA0sazeooa2wiJ9P9L31Mn5APZBJj5H8HjyKdvOmJ8neQn
+b77Tya11Q70U57uDq69l0rl58fpy650uTwYaLNGWmUdTgOiGMWN05lvIVNrQd/R
gP+VEQDGsTH6kqOCy9gyLCmn9q9I7l0t9lwcu5TP52Xy9vqVq9rb388MkcPcsWk8
cYPvD8RcSaywZUV3YJgbYozBfVuf5rLVus6D54pMXe3N12KGaNBt8kk4co4jBwvh
b//1urA82cdlEAZ/kiqHXjRMq/ht+dxtb6sSVOJ9frxPLuc7g1z4ORC+Z0PTS5WC
zB0hMzPnTwXeqHcYpV4wP/vGtgZGpLevBkK7pKVdqKZykV8BS4FiT4HFp6Rghxs3
dxAz7JjQUle6KOX7YfuHdpLnyZFWQvLYyTn946xGKpw2QH/iWLwECpet2I87QzVs
QkEkGygPhK4QcGccxz9N
=h5xk
-----END PGP SIGNATURE-----
Merge tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC platform updates from Olof Johansson:
"New and/or improved SoC support for this release:
Marvell Berlin:
- Enable standard DT-based cpufreq
- Add CPU hotplug support
Freescale:
- Ethernet init for i.MX7D
- Suspend/resume support for i.MX6UL
Allwinner:
- Support for R8 chipset (used on NTC's $9 C.H.I.P board)
Mediatek:
- SMP support for some platforms
Uniphier:
- L2 support
- Cleaned up SMP support, etc.
plus a handful of other patches around above functionality, and a few
other smaller changes"
* tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (42 commits)
ARM: uniphier: rework SMP operations to use trampoline code
ARM: uniphier: add outer cache support
Documentation: EXYNOS: Update bootloader interface on exynos542x
ARM: mvebu: add broken-idle option
ARM: orion5x: use mac_pton() helper
ARM: at91: pm: at91_pm_suspend_in_sram() must be 8-byte aligned
ARM: sunxi: Add R8 support
ARM: digicolor: select pinctrl/gpio driver
arm: berlin: add CPU hotplug support
arm: berlin: use non-self-cleared reset register to reset cpu
ARM: mediatek: add smp bringup code
ARM: mediatek: enable gpt6 on boot up to make arch timer working
soc: mediatek: Fix random hang up issue while kernel init
soc: ti: qmss: make acc queue support optional in the driver
soc: ti: add firmware file name as part of the driver
Documentation: dt: soc: Add description for knav qmss driver
ARM: S3C64XX: Use PWM lookup table for mach-smartq
ARM: S3C64XX: Use PWM lookup table for mach-hmt
ARM: S3C64XX: Use PWM lookup table for mach-crag6410
ARM: S3C64XX: Use PWM lookup table for smdk6410
...
This commit is contained in:
commit
56e0464980
70 changed files with 1888 additions and 296 deletions
|
|
@ -123,29 +123,23 @@ choice
|
|||
0x80020000 | 0xf0020000 | UART8
|
||||
0x80024000 | 0xf0024000 | UART9
|
||||
|
||||
config AT91_DEBUG_LL_DBGU0
|
||||
bool "Kernel low-level debugging on rm9200, 9260/9g20, 9261/9g10, 9rl, 9x5, 9n12"
|
||||
select DEBUG_AT91_UART
|
||||
config DEBUG_AT91_UART
|
||||
bool "Kernel low-level debugging on Atmel SoCs"
|
||||
depends on ARCH_AT91
|
||||
depends on SOC_AT91RM9200 || SOC_AT91SAM9
|
||||
help
|
||||
Say Y here if you want the debug print routines to direct
|
||||
their output to the serial port on atmel devices.
|
||||
|
||||
config AT91_DEBUG_LL_DBGU1
|
||||
bool "Kernel low-level debugging on 9263, 9g45 and sama5d3"
|
||||
select DEBUG_AT91_UART
|
||||
depends on ARCH_AT91
|
||||
depends on SOC_AT91SAM9 || SOC_SAMA5
|
||||
SOC DEBUG_UART_PHYS DEBUG_UART_VIRT PORT
|
||||
rm9200, 9260/9g20, 0xfffff200 0xfefff200 DBGU
|
||||
9261/9g10, 9rl
|
||||
9263, 9g45, sama5d3 0xffffee00 0xfeffee00 DBGU
|
||||
sama5d4 0xfc00c000 0xfb00c000 USART3
|
||||
sama5d4 0xfc069000 0xfb069000 DBGU
|
||||
sama5d2 0xf8020000 0xf7020000 UART1
|
||||
|
||||
config AT91_DEBUG_LL_DBGU2
|
||||
bool "Kernel low-level debugging on sama5d4"
|
||||
select DEBUG_AT91_UART
|
||||
depends on ARCH_AT91
|
||||
depends on SOC_SAMA5
|
||||
|
||||
config AT91_DEBUG_LL_DBGU3
|
||||
bool "Kernel low-level debugging on sama5d2"
|
||||
select DEBUG_AT91_UART
|
||||
depends on ARCH_AT91
|
||||
depends on SOC_SAMA5
|
||||
Please adjust DEBUG_UART_PHYS configuration options based on
|
||||
your needs.
|
||||
|
||||
config DEBUG_BCM2835
|
||||
bool "Kernel low-level debugging on BCM2835 PL011 UART"
|
||||
|
|
@ -1249,10 +1243,6 @@ choice
|
|||
|
||||
endchoice
|
||||
|
||||
config DEBUG_AT91_UART
|
||||
bool
|
||||
depends on ARCH_AT91
|
||||
|
||||
config DEBUG_EXYNOS_UART
|
||||
bool
|
||||
|
||||
|
|
@ -1485,7 +1475,8 @@ config DEBUG_UART_PHYS
|
|||
DEBUG_RMOBILE_SCIFA0 || DEBUG_RMOBILE_SCIFA1 || \
|
||||
DEBUG_RMOBILE_SCIFA4 || DEBUG_S3C24XX_UART || \
|
||||
DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART || \
|
||||
DEBUG_SIRFSOC_UART || DEBUG_DIGICOLOR_UA0
|
||||
DEBUG_SIRFSOC_UART || DEBUG_DIGICOLOR_UA0 || \
|
||||
DEBUG_AT91_UART
|
||||
|
||||
config DEBUG_UART_VIRT
|
||||
hex "Virtual base address of debug UART"
|
||||
|
|
|
|||
46
arch/arm/include/asm/hardware/cache-uniphier.h
Normal file
46
arch/arm/include/asm/hardware/cache-uniphier.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __CACHE_UNIPHIER_H
|
||||
#define __CACHE_UNIPHIER_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifdef CONFIG_CACHE_UNIPHIER
|
||||
int uniphier_cache_init(void);
|
||||
int uniphier_cache_l2_is_enabled(void);
|
||||
void uniphier_cache_l2_touch_range(unsigned long start, unsigned long end);
|
||||
void uniphier_cache_l2_set_locked_ways(u32 way_mask);
|
||||
#else
|
||||
static inline int uniphier_cache_init(void)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int uniphier_cache_l2_is_enabled(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void uniphier_cache_l2_touch_range(unsigned long start,
|
||||
unsigned long end)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void uniphier_cache_l2_set_locked_ways(u32 way_mask)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __CACHE_UNIPHIER_H */
|
||||
|
|
@ -9,32 +9,22 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_AT91_DEBUG_LL_DBGU0)
|
||||
#define AT91_DBGU 0xfffff200 /* AT91_BASE_DBGU0 */
|
||||
#elif defined(CONFIG_AT91_DEBUG_LL_DBGU1)
|
||||
#define AT91_DBGU 0xffffee00 /* AT91_BASE_DBGU1 */
|
||||
#elif defined(CONFIG_AT91_DEBUG_LL_DBGU2)
|
||||
/* On sama5d4, use USART3 as low level serial console */
|
||||
#define AT91_DBGU 0xfc00c000 /* SAMA5D4_BASE_USART3 */
|
||||
#else
|
||||
/* On sama5d2, use UART1 as low level serial console */
|
||||
#define AT91_DBGU 0xf8020000
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
#define AT91_IO_P2V(x) ((x) - 0x01000000)
|
||||
#else
|
||||
#define AT91_IO_P2V(x) (x)
|
||||
#endif
|
||||
|
||||
#define CONFIG_DEBUG_UART_VIRT AT91_IO_P2V(CONFIG_DEBUG_UART_PHYS)
|
||||
|
||||
#define AT91_DBGU_SR (0x14) /* Status Register */
|
||||
#define AT91_DBGU_THR (0x1c) /* Transmitter Holding Register */
|
||||
#define AT91_DBGU_TXRDY (1 << 1) /* Transmitter Ready */
|
||||
#define AT91_DBGU_TXEMPTY (1 << 9) /* Transmitter Empty */
|
||||
|
||||
.macro addruart, rp, rv, tmp
|
||||
ldr \rp, =AT91_DBGU @ System peripherals (phys address)
|
||||
ldr \rv, =AT91_IO_P2V(AT91_DBGU) @ System peripherals (virt address)
|
||||
ldr \rp, =CONFIG_DEBUG_UART_PHYS @ System peripherals (phys address)
|
||||
ldr \rv, =CONFIG_DEBUG_UART_VIRT @ System peripherals (virt address)
|
||||
.endm
|
||||
|
||||
.macro senduart,rd,rx
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include <linux/export.h>
|
||||
|
||||
#include <asm/hardware/cache-l2x0.h>
|
||||
#include <asm/hardware/cache-uniphier.h>
|
||||
#include <asm/outercache.h>
|
||||
#include <asm/exception.h>
|
||||
#include <asm/mach/arch.h>
|
||||
|
|
@ -97,6 +98,8 @@ void __init init_IRQ(void)
|
|||
if (ret)
|
||||
pr_err("L2C: failed to init: %d\n", ret);
|
||||
}
|
||||
|
||||
uniphier_cache_init();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MULTI_IRQ_HANDLER
|
||||
|
|
|
|||
|
|
@ -80,6 +80,8 @@ tmp2 .req r5
|
|||
* @r2: base address of second SDRAM Controller or 0 if not present
|
||||
* @r3: pm information
|
||||
*/
|
||||
/* at91_pm_suspend_in_sram must be 8-byte aligned per the requirements of fncpy() */
|
||||
.align 3
|
||||
ENTRY(at91_pm_suspend_in_sram)
|
||||
/* Save registers on stack */
|
||||
stmfd sp!, {r4 - r12, lr}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,20 @@ config ARCH_BCM_CYGNUS
|
|||
BCM11300, BCM11320, BCM11350, BCM11360,
|
||||
BCM58300, BCM58302, BCM58303, BCM58305.
|
||||
|
||||
config ARCH_BCM_NSP
|
||||
bool "Broadcom Northstar Plus SoC Support" if ARCH_MULTI_V7
|
||||
select ARCH_BCM_IPROC
|
||||
select ARM_ERRATA_754322
|
||||
select ARM_ERRATA_775420
|
||||
help
|
||||
Support for Broadcom Northstar Plus SoC.
|
||||
Broadcom Northstar Plus family of SoCs are used for switching control
|
||||
and management applications as well as residential router/gateway
|
||||
applications. The SoC features dual core Cortex A9 ARM CPUs,
|
||||
integrating several peripheral interfaces including multiple Gigabit
|
||||
Ethernet PHYs, DDR3 memory, PCIE Gen-2, USB 2.0 and USB 3.0, serial and
|
||||
NAND flash, SATA and several other IO controllers.
|
||||
|
||||
config ARCH_BCM_5301X
|
||||
bool "Broadcom BCM470X / BCM5301X ARM SoC" if ARCH_MULTI_V7
|
||||
select ARCH_BCM_IPROC
|
||||
|
|
@ -147,6 +161,7 @@ config ARCH_BRCMSTB
|
|||
select BCM7120_L2_IRQ
|
||||
select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
|
||||
select ARCH_WANT_OPTIONAL_GPIOLIB
|
||||
select SOC_BRCMSTB
|
||||
help
|
||||
Say Y if you intend to run the kernel on a Broadcom ARM-based STB
|
||||
chipset.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (C) 2012-2014 Broadcom Corporation
|
||||
# Copyright (C) 2012-2015 Broadcom Corporation
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
|
|
@ -13,6 +13,9 @@
|
|||
# Cygnus
|
||||
obj-$(CONFIG_ARCH_BCM_CYGNUS) += bcm_cygnus.o
|
||||
|
||||
# Northstar Plus
|
||||
obj-$(CONFIG_ARCH_BCM_NSP) += bcm_nsp.o
|
||||
|
||||
# BCM281XX
|
||||
obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o
|
||||
|
||||
|
|
|
|||
25
arch/arm/mach-bcm/bcm_nsp.c
Normal file
25
arch/arm/mach-bcm/bcm_nsp.c
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Broadcom Corporation
|
||||
*
|
||||
* 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 version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <asm/mach/arch.h>
|
||||
|
||||
static const char *const bcm_nsp_dt_compat[] __initconst = {
|
||||
"brcm,nsp",
|
||||
NULL,
|
||||
};
|
||||
|
||||
DT_MACHINE_START(NSP_DT, "Broadcom Northstar Plus SoC")
|
||||
.l2c_aux_val = 0,
|
||||
.l2c_aux_mask = ~0,
|
||||
.dt_compat = bcm_nsp_dt_compat,
|
||||
MACHINE_END
|
||||
|
|
@ -12,11 +12,19 @@
|
|||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/soc/brcmstb/brcmstb.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
|
||||
static void __init brcmstb_init_irq(void)
|
||||
{
|
||||
irqchip_init();
|
||||
brcmstb_biuctrl_init();
|
||||
}
|
||||
|
||||
static const char *const brcmstb_match[] __initconst = {
|
||||
"brcm,bcm7445",
|
||||
"brcm,brcmstb",
|
||||
|
|
@ -25,4 +33,5 @@ static const char *const brcmstb_match[] __initconst = {
|
|||
|
||||
DT_MACHINE_START(BRCMSTB, "Broadcom STB (Flattened Device Tree)")
|
||||
.dt_compat = brcmstb_match,
|
||||
.init_irq = brcmstb_init_irq,
|
||||
MACHINE_END
|
||||
|
|
|
|||
|
|
@ -18,6 +18,11 @@
|
|||
#include <asm/hardware/cache-l2x0.h>
|
||||
#include <asm/mach/arch.h>
|
||||
|
||||
static void __init berlin_init_late(void)
|
||||
{
|
||||
platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
|
||||
}
|
||||
|
||||
static const char * const berlin_dt_compat[] = {
|
||||
"marvell,berlin",
|
||||
NULL,
|
||||
|
|
@ -25,6 +30,7 @@ static const char * const berlin_dt_compat[] = {
|
|||
|
||||
DT_MACHINE_START(BERLIN_DT, "Marvell Berlin")
|
||||
.dt_compat = berlin_dt_compat,
|
||||
.init_late = berlin_init_late,
|
||||
/*
|
||||
* with DT probing for L2CCs, berlin_init_machine can be removed.
|
||||
* Note: 88DE3005 (Armada 1500-mini) uses pl310 l2cc
|
||||
|
|
|
|||
|
|
@ -14,10 +14,16 @@
|
|||
#include <linux/of_address.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/cp15.h>
|
||||
#include <asm/smp_plat.h>
|
||||
#include <asm/smp_scu.h>
|
||||
|
||||
#define CPU_RESET 0x00
|
||||
/*
|
||||
* There are two reset registers, one with self-clearing (SC)
|
||||
* reset and one with non-self-clearing reset (NON_SC).
|
||||
*/
|
||||
#define CPU_RESET_SC 0x00
|
||||
#define CPU_RESET_NON_SC 0x20
|
||||
|
||||
#define RESET_VECT 0x00
|
||||
#define SW_RESET_ADDR 0x94
|
||||
|
|
@ -30,9 +36,11 @@ static inline void berlin_perform_reset_cpu(unsigned int cpu)
|
|||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(cpu_ctrl + CPU_RESET);
|
||||
val = readl(cpu_ctrl + CPU_RESET_NON_SC);
|
||||
val &= ~BIT(cpu_logical_map(cpu));
|
||||
writel(val, cpu_ctrl + CPU_RESET_NON_SC);
|
||||
val |= BIT(cpu_logical_map(cpu));
|
||||
writel(val, cpu_ctrl + CPU_RESET);
|
||||
writel(val, cpu_ctrl + CPU_RESET_NON_SC);
|
||||
}
|
||||
|
||||
static int berlin_boot_secondary(unsigned int cpu, struct task_struct *idle)
|
||||
|
|
@ -91,8 +99,32 @@ unmap_scu:
|
|||
iounmap(scu_base);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
static void berlin_cpu_die(unsigned int cpu)
|
||||
{
|
||||
v7_exit_coherency_flush(louis);
|
||||
while (1)
|
||||
cpu_do_idle();
|
||||
}
|
||||
|
||||
static int berlin_cpu_kill(unsigned int cpu)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(cpu_ctrl + CPU_RESET_NON_SC);
|
||||
val &= ~BIT(cpu_logical_map(cpu));
|
||||
writel(val, cpu_ctrl + CPU_RESET_NON_SC);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct smp_operations berlin_smp_ops __initdata = {
|
||||
.smp_prepare_cpus = berlin_smp_prepare_cpus,
|
||||
.smp_boot_secondary = berlin_boot_secondary,
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
.cpu_die = berlin_cpu_die,
|
||||
.cpu_kill = berlin_cpu_kill,
|
||||
#endif
|
||||
};
|
||||
CPU_METHOD_OF_DECLARE(berlin_smp, "marvell,berlin-smp", &berlin_smp_ops);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
config ARCH_DIGICOLOR
|
||||
bool "Conexant Digicolor SoC Support"
|
||||
depends on ARCH_MULTI_V7
|
||||
select ARCH_REQUIRE_GPIOLIB
|
||||
select CLKSRC_MMIO
|
||||
select DIGICOLOR_TIMER
|
||||
select GENERIC_IRQ_CHIP
|
||||
select MFD_SYSCON
|
||||
select PINCTRL
|
||||
select PINCTRL_DIGICOLOR
|
||||
|
|
|
|||
|
|
@ -131,6 +131,7 @@ void imx6q_pm_init(void);
|
|||
void imx6dl_pm_init(void);
|
||||
void imx6sl_pm_init(void);
|
||||
void imx6sx_pm_init(void);
|
||||
void imx6ul_pm_init(void);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
void imx51_pm_init(void);
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ static void __init imx6ul_init_machine(void)
|
|||
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
|
||||
imx6ul_enet_init();
|
||||
imx_anatop_init();
|
||||
imx6ul_pm_init();
|
||||
}
|
||||
|
||||
static void __init imx6ul_init_irq(void)
|
||||
|
|
@ -74,6 +75,13 @@ static void __init imx6ul_init_irq(void)
|
|||
imx_init_revision_from_anatop();
|
||||
imx_src_init();
|
||||
irqchip_init();
|
||||
imx6_pm_ccm_init("fsl,imx6ul-ccm");
|
||||
}
|
||||
|
||||
static void __init imx6ul_init_late(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ))
|
||||
platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0);
|
||||
}
|
||||
|
||||
static const char *imx6ul_dt_compat[] __initconst = {
|
||||
|
|
@ -84,5 +92,6 @@ static const char *imx6ul_dt_compat[] __initconst = {
|
|||
DT_MACHINE_START(IMX6UL, "Freescale i.MX6 Ultralite (Device Tree)")
|
||||
.init_irq = imx6ul_init_irq,
|
||||
.init_machine = imx6ul_init_machine,
|
||||
.init_late = imx6ul_init_late,
|
||||
.dt_compat = imx6ul_dt_compat,
|
||||
MACHINE_END
|
||||
|
|
|
|||
|
|
@ -6,12 +6,85 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mfd/syscon/imx7-iomuxc-gpr.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/map.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static int ar8031_phy_fixup(struct phy_device *dev)
|
||||
{
|
||||
u16 val;
|
||||
|
||||
/* Set RGMII IO voltage to 1.8V */
|
||||
phy_write(dev, 0x1d, 0x1f);
|
||||
phy_write(dev, 0x1e, 0x8);
|
||||
|
||||
/* disable phy AR8031 SmartEEE function. */
|
||||
phy_write(dev, 0xd, 0x3);
|
||||
phy_write(dev, 0xe, 0x805d);
|
||||
phy_write(dev, 0xd, 0x4003);
|
||||
val = phy_read(dev, 0xe);
|
||||
val &= ~(0x1 << 8);
|
||||
phy_write(dev, 0xe, val);
|
||||
|
||||
/* introduce tx clock delay */
|
||||
phy_write(dev, 0x1d, 0x5);
|
||||
val = phy_read(dev, 0x1e);
|
||||
val |= 0x0100;
|
||||
phy_write(dev, 0x1e, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm54220_phy_fixup(struct phy_device *dev)
|
||||
{
|
||||
/* enable RXC skew select RGMII copper mode */
|
||||
phy_write(dev, 0x1e, 0x21);
|
||||
phy_write(dev, 0x1f, 0x7ea8);
|
||||
phy_write(dev, 0x1e, 0x2f);
|
||||
phy_write(dev, 0x1f, 0x71b7);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define PHY_ID_AR8031 0x004dd074
|
||||
#define PHY_ID_BCM54220 0x600d8589
|
||||
|
||||
static void __init imx7d_enet_phy_init(void)
|
||||
{
|
||||
if (IS_BUILTIN(CONFIG_PHYLIB)) {
|
||||
phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff,
|
||||
ar8031_phy_fixup);
|
||||
phy_register_fixup_for_uid(PHY_ID_BCM54220, 0xffffffff,
|
||||
bcm54220_phy_fixup);
|
||||
}
|
||||
}
|
||||
|
||||
static void __init imx7d_enet_clk_sel(void)
|
||||
{
|
||||
struct regmap *gpr;
|
||||
|
||||
gpr = syscon_regmap_lookup_by_compatible("fsl,imx7d-iomuxc-gpr");
|
||||
if (!IS_ERR(gpr)) {
|
||||
regmap_update_bits(gpr, IOMUXC_GPR1, IMX7D_GPR1_ENET_TX_CLK_SEL_MASK, 0);
|
||||
regmap_update_bits(gpr, IOMUXC_GPR1, IMX7D_GPR1_ENET_CLK_DIR_MASK, 0);
|
||||
} else {
|
||||
pr_err("failed to find fsl,imx7d-iomux-gpr regmap\n");
|
||||
}
|
||||
}
|
||||
|
||||
static inline void imx7d_enet_init(void)
|
||||
{
|
||||
imx7d_enet_phy_init();
|
||||
imx7d_enet_clk_sel();
|
||||
}
|
||||
|
||||
static void __init imx7d_init_machine(void)
|
||||
{
|
||||
struct device *parent;
|
||||
|
|
@ -22,6 +95,7 @@ static void __init imx7d_init_machine(void)
|
|||
|
||||
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
|
||||
imx_anatop_init();
|
||||
imx7d_enet_init();
|
||||
}
|
||||
|
||||
static void __init imx7d_init_irq(void)
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ struct imx6_pm_socdata {
|
|||
const char *src_compat;
|
||||
const char *iomuxc_compat;
|
||||
const char *gpc_compat;
|
||||
const char *pl310_compat;
|
||||
const u32 mmdc_io_num;
|
||||
const u32 *mmdc_io_offset;
|
||||
};
|
||||
|
|
@ -137,11 +138,19 @@ static const u32 imx6sx_mmdc_io_offset[] __initconst = {
|
|||
0x330, 0x334, 0x338, 0x33c, /* SDQS0 ~ SDQS3 */
|
||||
};
|
||||
|
||||
static const u32 imx6ul_mmdc_io_offset[] __initconst = {
|
||||
0x244, 0x248, 0x24c, 0x250, /* DQM0, DQM1, RAS, CAS */
|
||||
0x27c, 0x498, 0x4a4, 0x490, /* SDCLK0, GPR_B0DS-B1DS, GPR_ADDS */
|
||||
0x280, 0x284, 0x260, 0x264, /* SDQS0~1, SODT0, SODT1 */
|
||||
0x494, 0x4b0, /* MODE_CTL, MODE, */
|
||||
};
|
||||
|
||||
static const struct imx6_pm_socdata imx6q_pm_data __initconst = {
|
||||
.mmdc_compat = "fsl,imx6q-mmdc",
|
||||
.src_compat = "fsl,imx6q-src",
|
||||
.iomuxc_compat = "fsl,imx6q-iomuxc",
|
||||
.gpc_compat = "fsl,imx6q-gpc",
|
||||
.pl310_compat = "arm,pl310-cache",
|
||||
.mmdc_io_num = ARRAY_SIZE(imx6q_mmdc_io_offset),
|
||||
.mmdc_io_offset = imx6q_mmdc_io_offset,
|
||||
};
|
||||
|
|
@ -151,6 +160,7 @@ static const struct imx6_pm_socdata imx6dl_pm_data __initconst = {
|
|||
.src_compat = "fsl,imx6q-src",
|
||||
.iomuxc_compat = "fsl,imx6dl-iomuxc",
|
||||
.gpc_compat = "fsl,imx6q-gpc",
|
||||
.pl310_compat = "arm,pl310-cache",
|
||||
.mmdc_io_num = ARRAY_SIZE(imx6dl_mmdc_io_offset),
|
||||
.mmdc_io_offset = imx6dl_mmdc_io_offset,
|
||||
};
|
||||
|
|
@ -160,6 +170,7 @@ static const struct imx6_pm_socdata imx6sl_pm_data __initconst = {
|
|||
.src_compat = "fsl,imx6sl-src",
|
||||
.iomuxc_compat = "fsl,imx6sl-iomuxc",
|
||||
.gpc_compat = "fsl,imx6sl-gpc",
|
||||
.pl310_compat = "arm,pl310-cache",
|
||||
.mmdc_io_num = ARRAY_SIZE(imx6sl_mmdc_io_offset),
|
||||
.mmdc_io_offset = imx6sl_mmdc_io_offset,
|
||||
};
|
||||
|
|
@ -169,10 +180,21 @@ static const struct imx6_pm_socdata imx6sx_pm_data __initconst = {
|
|||
.src_compat = "fsl,imx6sx-src",
|
||||
.iomuxc_compat = "fsl,imx6sx-iomuxc",
|
||||
.gpc_compat = "fsl,imx6sx-gpc",
|
||||
.pl310_compat = "arm,pl310-cache",
|
||||
.mmdc_io_num = ARRAY_SIZE(imx6sx_mmdc_io_offset),
|
||||
.mmdc_io_offset = imx6sx_mmdc_io_offset,
|
||||
};
|
||||
|
||||
static const struct imx6_pm_socdata imx6ul_pm_data __initconst = {
|
||||
.mmdc_compat = "fsl,imx6ul-mmdc",
|
||||
.src_compat = "fsl,imx6ul-src",
|
||||
.iomuxc_compat = "fsl,imx6ul-iomuxc",
|
||||
.gpc_compat = "fsl,imx6ul-gpc",
|
||||
.pl310_compat = NULL,
|
||||
.mmdc_io_num = ARRAY_SIZE(imx6ul_mmdc_io_offset),
|
||||
.mmdc_io_offset = imx6ul_mmdc_io_offset,
|
||||
};
|
||||
|
||||
/*
|
||||
* This structure is for passing necessary data for low level ocram
|
||||
* suspend code(arch/arm/mach-imx/suspend-imx6.S), if this struct
|
||||
|
|
@ -290,7 +312,7 @@ int imx6_set_lpm(enum mxc_cpu_pwr_mode mode)
|
|||
val |= BM_CLPCR_SBYOS;
|
||||
if (cpu_is_imx6sl())
|
||||
val |= BM_CLPCR_BYPASS_PMIC_READY;
|
||||
if (cpu_is_imx6sl() || cpu_is_imx6sx())
|
||||
if (cpu_is_imx6sl() || cpu_is_imx6sx() || cpu_is_imx6ul())
|
||||
val |= BM_CLPCR_BYP_MMDC_CH0_LPM_HS;
|
||||
else
|
||||
val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS;
|
||||
|
|
@ -330,6 +352,10 @@ static int imx6q_suspend_finish(unsigned long val)
|
|||
* as we need to float DDR IO.
|
||||
*/
|
||||
local_flush_tlb_all();
|
||||
/* check if need to flush internal L2 cache */
|
||||
if (!((struct imx6_cpu_pm_info *)
|
||||
suspend_ocram_base)->l2_base.vbase)
|
||||
flush_cache_all();
|
||||
imx6_suspend_in_ocram_fn(suspend_ocram_base);
|
||||
}
|
||||
|
||||
|
|
@ -470,6 +496,7 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata)
|
|||
suspend_ocram_base = __arm_ioremap_exec(ocram_pbase,
|
||||
MX6Q_SUSPEND_OCRAM_SIZE, false);
|
||||
|
||||
memset(suspend_ocram_base, 0, sizeof(*pm_info));
|
||||
pm_info = suspend_ocram_base;
|
||||
pm_info->pbase = ocram_pbase;
|
||||
pm_info->resume_addr = virt_to_phys(v7_cpu_resume);
|
||||
|
|
@ -505,11 +532,13 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata)
|
|||
goto gpc_map_failed;
|
||||
}
|
||||
|
||||
ret = imx6_pm_get_base(&pm_info->l2_base, "arm,pl310-cache");
|
||||
if (ret) {
|
||||
pr_warn("%s: failed to get pl310-cache base %d!\n",
|
||||
__func__, ret);
|
||||
goto pl310_cache_map_failed;
|
||||
if (socdata->pl310_compat) {
|
||||
ret = imx6_pm_get_base(&pm_info->l2_base, socdata->pl310_compat);
|
||||
if (ret) {
|
||||
pr_warn("%s: failed to get pl310-cache base %d!\n",
|
||||
__func__, ret);
|
||||
goto pl310_cache_map_failed;
|
||||
}
|
||||
}
|
||||
|
||||
pm_info->ddr_type = imx_mmdc_get_ddr_type();
|
||||
|
|
@ -610,3 +639,8 @@ void __init imx6sx_pm_init(void)
|
|||
{
|
||||
imx6_pm_common_init(&imx6sx_pm_data);
|
||||
}
|
||||
|
||||
void __init imx6ul_pm_init(void)
|
||||
{
|
||||
imx6_pm_common_init(&imx6ul_pm_data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,12 +79,15 @@
|
|||
/* sync L2 cache to drain L2's buffers to DRAM. */
|
||||
#ifdef CONFIG_CACHE_L2X0
|
||||
ldr r11, [r0, #PM_INFO_MX6Q_L2_V_OFFSET]
|
||||
teq r11, #0
|
||||
beq 6f
|
||||
mov r6, #0x0
|
||||
str r6, [r11, #L2X0_CACHE_SYNC]
|
||||
1:
|
||||
ldr r6, [r11, #L2X0_CACHE_SYNC]
|
||||
ands r6, r6, #0x1
|
||||
bne 1b
|
||||
6:
|
||||
#endif
|
||||
|
||||
.endm
|
||||
|
|
|
|||
|
|
@ -1 +1,4 @@
|
|||
ifeq ($(CONFIG_SMP),y)
|
||||
obj-$(CONFIG_ARCH_MEDIATEK) += platsmp.o
|
||||
endif
|
||||
obj-$(CONFIG_ARCH_MEDIATEK) += mediatek.o
|
||||
|
|
|
|||
|
|
@ -16,6 +16,32 @@
|
|||
*/
|
||||
#include <linux/init.h>
|
||||
#include <asm/mach/arch.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clocksource.h>
|
||||
|
||||
|
||||
#define GPT6_CON_MT65xx 0x10008060
|
||||
#define GPT_ENABLE 0x31
|
||||
|
||||
static void __init mediatek_timer_init(void)
|
||||
{
|
||||
void __iomem *gpt_base;
|
||||
|
||||
if (of_machine_is_compatible("mediatek,mt6589") ||
|
||||
of_machine_is_compatible("mediatek,mt8135") ||
|
||||
of_machine_is_compatible("mediatek,mt8127")) {
|
||||
/* turn on GPT6 which ungates arch timer clocks */
|
||||
gpt_base = ioremap(GPT6_CON_MT65xx, 0x04);
|
||||
|
||||
/* enable clock and set to free-run */
|
||||
writel(GPT_ENABLE, gpt_base);
|
||||
iounmap(gpt_base);
|
||||
}
|
||||
|
||||
of_clk_init(NULL);
|
||||
clocksource_probe();
|
||||
};
|
||||
|
||||
static const char * const mediatek_board_dt_compat[] = {
|
||||
"mediatek,mt6589",
|
||||
|
|
@ -27,4 +53,5 @@ static const char * const mediatek_board_dt_compat[] = {
|
|||
|
||||
DT_MACHINE_START(MEDIATEK_DT, "Mediatek Cortex-A7 (Device Tree)")
|
||||
.dt_compat = mediatek_board_dt_compat,
|
||||
.init_time = mediatek_timer_init,
|
||||
MACHINE_END
|
||||
|
|
|
|||
141
arch/arm/mach-mediatek/platsmp.c
Normal file
141
arch/arm/mach-mediatek/platsmp.c
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* arch/arm/mach-mediatek/platsmp.c
|
||||
*
|
||||
* Copyright (c) 2014 Mediatek Inc.
|
||||
* Author: Shunli Wang <shunli.wang@mediatek.com>
|
||||
* Yingjoe Chen <yingjoe.chen@mediatek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#include <linux/io.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/threads.h>
|
||||
|
||||
#define MTK_MAX_CPU 8
|
||||
#define MTK_SMP_REG_SIZE 0x1000
|
||||
|
||||
struct mtk_smp_boot_info {
|
||||
unsigned long smp_base;
|
||||
unsigned int jump_reg;
|
||||
unsigned int core_keys[MTK_MAX_CPU - 1];
|
||||
unsigned int core_regs[MTK_MAX_CPU - 1];
|
||||
};
|
||||
|
||||
static const struct mtk_smp_boot_info mtk_mt8135_tz_boot = {
|
||||
0x80002000, 0x3fc,
|
||||
{ 0x534c4131, 0x4c415332, 0x41534c33 },
|
||||
{ 0x3f8, 0x3f8, 0x3f8 },
|
||||
};
|
||||
|
||||
static const struct mtk_smp_boot_info mtk_mt6589_boot = {
|
||||
0x10002000, 0x34,
|
||||
{ 0x534c4131, 0x4c415332, 0x41534c33 },
|
||||
{ 0x38, 0x3c, 0x40 },
|
||||
};
|
||||
|
||||
static const struct of_device_id mtk_tz_smp_boot_infos[] __initconst = {
|
||||
{ .compatible = "mediatek,mt8135", .data = &mtk_mt8135_tz_boot },
|
||||
{ .compatible = "mediatek,mt8127", .data = &mtk_mt8135_tz_boot },
|
||||
};
|
||||
|
||||
static const struct of_device_id mtk_smp_boot_infos[] __initconst = {
|
||||
{ .compatible = "mediatek,mt6589", .data = &mtk_mt6589_boot },
|
||||
};
|
||||
|
||||
static void __iomem *mtk_smp_base;
|
||||
static const struct mtk_smp_boot_info *mtk_smp_info;
|
||||
|
||||
static int mtk_boot_secondary(unsigned int cpu, struct task_struct *idle)
|
||||
{
|
||||
if (!mtk_smp_base)
|
||||
return -EINVAL;
|
||||
|
||||
if (!mtk_smp_info->core_keys[cpu-1])
|
||||
return -EINVAL;
|
||||
|
||||
writel_relaxed(mtk_smp_info->core_keys[cpu-1],
|
||||
mtk_smp_base + mtk_smp_info->core_regs[cpu-1]);
|
||||
|
||||
arch_send_wakeup_ipi_mask(cpumask_of(cpu));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init __mtk_smp_prepare_cpus(unsigned int max_cpus, int trustzone)
|
||||
{
|
||||
int i, num;
|
||||
const struct of_device_id *infos;
|
||||
|
||||
if (trustzone) {
|
||||
num = ARRAY_SIZE(mtk_tz_smp_boot_infos);
|
||||
infos = mtk_tz_smp_boot_infos;
|
||||
} else {
|
||||
num = ARRAY_SIZE(mtk_smp_boot_infos);
|
||||
infos = mtk_smp_boot_infos;
|
||||
}
|
||||
|
||||
/* Find smp boot info for this SoC */
|
||||
for (i = 0; i < num; i++) {
|
||||
if (of_machine_is_compatible(infos[i].compatible)) {
|
||||
mtk_smp_info = infos[i].data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mtk_smp_info) {
|
||||
pr_err("%s: Device is not supported\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (trustzone) {
|
||||
/* smp_base(trustzone-bootinfo) is reserved by device tree */
|
||||
mtk_smp_base = phys_to_virt(mtk_smp_info->smp_base);
|
||||
} else {
|
||||
mtk_smp_base = ioremap(mtk_smp_info->smp_base, MTK_SMP_REG_SIZE);
|
||||
if (!mtk_smp_base) {
|
||||
pr_err("%s: Can't remap %lx\n", __func__,
|
||||
mtk_smp_info->smp_base);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* write the address of slave startup address into the system-wide
|
||||
* jump register
|
||||
*/
|
||||
writel_relaxed(virt_to_phys(secondary_startup_arm),
|
||||
mtk_smp_base + mtk_smp_info->jump_reg);
|
||||
}
|
||||
|
||||
static void __init mtk_tz_smp_prepare_cpus(unsigned int max_cpus)
|
||||
{
|
||||
__mtk_smp_prepare_cpus(max_cpus, 1);
|
||||
}
|
||||
|
||||
static void __init mtk_smp_prepare_cpus(unsigned int max_cpus)
|
||||
{
|
||||
__mtk_smp_prepare_cpus(max_cpus, 0);
|
||||
}
|
||||
|
||||
static struct smp_operations mt81xx_tz_smp_ops __initdata = {
|
||||
.smp_prepare_cpus = mtk_tz_smp_prepare_cpus,
|
||||
.smp_boot_secondary = mtk_boot_secondary,
|
||||
};
|
||||
CPU_METHOD_OF_DECLARE(mt81xx_tz_smp, "mediatek,mt81xx-tz-smp", &mt81xx_tz_smp_ops);
|
||||
|
||||
static struct smp_operations mt6589_smp_ops __initdata = {
|
||||
.smp_prepare_cpus = mtk_smp_prepare_cpus,
|
||||
.smp_boot_secondary = mtk_boot_secondary,
|
||||
};
|
||||
CPU_METHOD_OF_DECLARE(mt6589_smp, "mediatek,mt6589-smp", &mt6589_smp_ops);
|
||||
|
|
@ -19,4 +19,9 @@ config MACH_MESON8
|
|||
default ARCH_MESON
|
||||
select MESON6_TIMER
|
||||
|
||||
config MACH_MESON8B
|
||||
bool "Amlogic Meson8b SoCs support"
|
||||
default ARCH_MESON
|
||||
select MESON6_TIMER
|
||||
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
static const char * const meson_common_board_compat[] = {
|
||||
"amlogic,meson6",
|
||||
"amlogic,meson8",
|
||||
"amlogic,meson8b",
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
unsigned long coherency_phys_base;
|
||||
void __iomem *coherency_base;
|
||||
static void __iomem *coherency_cpu_base;
|
||||
static void __iomem *cpu_config_base;
|
||||
|
||||
/* Coherency fabric registers */
|
||||
#define IO_SYNC_BARRIER_CTL_OFFSET 0x0
|
||||
|
|
@ -65,6 +66,31 @@ static const struct of_device_id of_coherency_table[] = {
|
|||
int ll_enable_coherency(void);
|
||||
void ll_add_cpu_to_smp_group(void);
|
||||
|
||||
#define CPU_CONFIG_SHARED_L2 BIT(16)
|
||||
|
||||
/*
|
||||
* Disable the "Shared L2 Present" bit in CPU Configuration register
|
||||
* on Armada XP.
|
||||
*
|
||||
* The "Shared L2 Present" bit affects the "level of coherence" value
|
||||
* in the clidr CP15 register. Cache operation functions such as
|
||||
* "flush all" and "invalidate all" operate on all the cache levels
|
||||
* that included in the defined level of coherence. When HW I/O
|
||||
* coherency is used, this bit causes unnecessary flushes of the L2
|
||||
* cache.
|
||||
*/
|
||||
static void armada_xp_clear_shared_l2(void)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
if (!cpu_config_base)
|
||||
return;
|
||||
|
||||
reg = readl(cpu_config_base);
|
||||
reg &= ~CPU_CONFIG_SHARED_L2;
|
||||
writel(reg, cpu_config_base);
|
||||
}
|
||||
|
||||
static int mvebu_hwcc_notifier(struct notifier_block *nb,
|
||||
unsigned long event, void *__dev)
|
||||
{
|
||||
|
|
@ -85,9 +111,24 @@ static struct notifier_block mvebu_hwcc_pci_nb = {
|
|||
.notifier_call = mvebu_hwcc_notifier,
|
||||
};
|
||||
|
||||
static int armada_xp_clear_shared_l2_notifier_func(struct notifier_block *nfb,
|
||||
unsigned long action, void *hcpu)
|
||||
{
|
||||
if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
|
||||
armada_xp_clear_shared_l2();
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block armada_xp_clear_shared_l2_notifier = {
|
||||
.notifier_call = armada_xp_clear_shared_l2_notifier_func,
|
||||
.priority = 100,
|
||||
};
|
||||
|
||||
static void __init armada_370_coherency_init(struct device_node *np)
|
||||
{
|
||||
struct resource res;
|
||||
struct device_node *cpu_config_np;
|
||||
|
||||
of_address_to_resource(np, 0, &res);
|
||||
coherency_phys_base = res.start;
|
||||
|
|
@ -100,6 +141,23 @@ static void __init armada_370_coherency_init(struct device_node *np)
|
|||
sync_cache_w(&coherency_phys_base);
|
||||
coherency_base = of_iomap(np, 0);
|
||||
coherency_cpu_base = of_iomap(np, 1);
|
||||
|
||||
cpu_config_np = of_find_compatible_node(NULL, NULL,
|
||||
"marvell,armada-xp-cpu-config");
|
||||
if (!cpu_config_np)
|
||||
goto exit;
|
||||
|
||||
cpu_config_base = of_iomap(cpu_config_np, 0);
|
||||
if (!cpu_config_base) {
|
||||
of_node_put(cpu_config_np);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
of_node_put(cpu_config_np);
|
||||
|
||||
register_cpu_notifier(&armada_xp_clear_shared_l2_notifier);
|
||||
|
||||
exit:
|
||||
set_cpu_coherent();
|
||||
}
|
||||
|
||||
|
|
@ -204,6 +262,8 @@ int set_cpu_coherent(void)
|
|||
pr_warn("Coherency fabric is not initialized\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
armada_xp_clear_shared_l2();
|
||||
ll_add_cpu_to_smp_group();
|
||||
return ll_enable_coherency();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -379,6 +379,16 @@ static struct notifier_block mvebu_v7_cpu_pm_notifier = {
|
|||
|
||||
static struct platform_device mvebu_v7_cpuidle_device;
|
||||
|
||||
static int broken_idle(struct device_node *np)
|
||||
{
|
||||
if (of_property_read_bool(np, "broken-idle")) {
|
||||
pr_warn("CPU idle is currently broken: disabling\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __init int armada_370_cpuidle_init(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
|
|
@ -387,7 +397,9 @@ static __init int armada_370_cpuidle_init(void)
|
|||
np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric");
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
of_node_put(np);
|
||||
|
||||
if (broken_idle(np))
|
||||
goto end;
|
||||
|
||||
/*
|
||||
* On Armada 370, there is "a slow exit process from the deep
|
||||
|
|
@ -406,6 +418,8 @@ static __init int armada_370_cpuidle_init(void)
|
|||
mvebu_v7_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend;
|
||||
mvebu_v7_cpuidle_device.name = "cpuidle-armada-370";
|
||||
|
||||
end:
|
||||
of_node_put(np);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -422,6 +436,10 @@ static __init int armada_38x_cpuidle_init(void)
|
|||
"marvell,armada-380-coherency-fabric");
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
if (broken_idle(np))
|
||||
goto end;
|
||||
|
||||
of_node_put(np);
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL,
|
||||
|
|
@ -430,7 +448,6 @@ static __init int armada_38x_cpuidle_init(void)
|
|||
return -ENODEV;
|
||||
mpsoc_base = of_iomap(np, 0);
|
||||
BUG_ON(!mpsoc_base);
|
||||
of_node_put(np);
|
||||
|
||||
/* Set up reset mask when powering down the cpus */
|
||||
reg = readl(mpsoc_base + MPCORE_RESET_CTL);
|
||||
|
|
@ -450,6 +467,8 @@ static __init int armada_38x_cpuidle_init(void)
|
|||
mvebu_v7_cpuidle_device.dev.platform_data = armada_38x_cpu_suspend;
|
||||
mvebu_v7_cpuidle_device.name = "cpuidle-armada-38x";
|
||||
|
||||
end:
|
||||
of_node_put(np);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -460,12 +479,16 @@ static __init int armada_xp_cpuidle_init(void)
|
|||
np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric");
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
of_node_put(np);
|
||||
|
||||
if (broken_idle(np))
|
||||
goto end;
|
||||
|
||||
mvebu_cpu_resume = armada_370_xp_cpu_resume;
|
||||
mvebu_v7_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend;
|
||||
mvebu_v7_cpuidle_device.name = "cpuidle-armada-xp";
|
||||
|
||||
end:
|
||||
of_node_put(np);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ config MACH_KUROBOX_PRO
|
|||
|
||||
config MACH_DNS323
|
||||
bool "D-Link DNS-323"
|
||||
select GENERIC_NET_UTILS
|
||||
select I2C_BOARDINFO
|
||||
help
|
||||
Say 'Y' here if you want your kernel to support the
|
||||
|
|
@ -52,6 +53,7 @@ config MACH_DNS323
|
|||
|
||||
config MACH_TS209
|
||||
bool "QNAP TS-109/TS-209"
|
||||
select GENERIC_NET_UTILS
|
||||
help
|
||||
Say 'Y' here if you want your kernel to support the
|
||||
QNAP TS-109/TS-209 platform.
|
||||
|
|
@ -93,6 +95,7 @@ config MACH_LINKSTATION_LS_HGL
|
|||
|
||||
config MACH_TS409
|
||||
bool "QNAP TS-409"
|
||||
select GENERIC_NET_UTILS
|
||||
help
|
||||
Say 'Y' here if you want your kernel to support the
|
||||
QNAP TS-409 platform.
|
||||
|
|
|
|||
|
|
@ -173,42 +173,10 @@ static struct mv643xx_eth_platform_data dns323_eth_data = {
|
|||
.phy_addr = MV643XX_ETH_PHY_ADDR(8),
|
||||
};
|
||||
|
||||
/* dns323_parse_hex_*() taken from tsx09-common.c; should a common copy of these
|
||||
* functions be kept somewhere?
|
||||
*/
|
||||
static int __init dns323_parse_hex_nibble(char n)
|
||||
{
|
||||
if (n >= '0' && n <= '9')
|
||||
return n - '0';
|
||||
|
||||
if (n >= 'A' && n <= 'F')
|
||||
return n - 'A' + 10;
|
||||
|
||||
if (n >= 'a' && n <= 'f')
|
||||
return n - 'a' + 10;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int __init dns323_parse_hex_byte(const char *b)
|
||||
{
|
||||
int hi;
|
||||
int lo;
|
||||
|
||||
hi = dns323_parse_hex_nibble(b[0]);
|
||||
lo = dns323_parse_hex_nibble(b[1]);
|
||||
|
||||
if (hi < 0 || lo < 0)
|
||||
return -1;
|
||||
|
||||
return (hi << 4) | lo;
|
||||
}
|
||||
|
||||
static int __init dns323_read_mac_addr(void)
|
||||
{
|
||||
u_int8_t addr[6];
|
||||
int i;
|
||||
char *mac_page;
|
||||
void __iomem *mac_page;
|
||||
|
||||
/* MAC address is stored as a regular ol' string in /dev/mtdblock4
|
||||
* (0x007d0000-0x00800000) starting at offset 196480 (0x2ff80).
|
||||
|
|
@ -217,23 +185,8 @@ static int __init dns323_read_mac_addr(void)
|
|||
if (!mac_page)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Sanity check the string we're looking at */
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (*(mac_page + (i * 3) + 2) != ':') {
|
||||
goto error_fail;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
int byte;
|
||||
|
||||
byte = dns323_parse_hex_byte(mac_page + (i * 3));
|
||||
if (byte < 0) {
|
||||
goto error_fail;
|
||||
}
|
||||
|
||||
addr[i] = byte;
|
||||
}
|
||||
if (!mac_pton((__force const char *) mac_page, addr))
|
||||
goto error_fail;
|
||||
|
||||
iounmap(mac_page);
|
||||
printk("DNS-323: Found ethernet MAC address: %pM\n", addr);
|
||||
|
|
|
|||
|
|
@ -53,53 +53,12 @@ struct mv643xx_eth_platform_data qnap_tsx09_eth_data = {
|
|||
.phy_addr = MV643XX_ETH_PHY_ADDR(8),
|
||||
};
|
||||
|
||||
static int __init qnap_tsx09_parse_hex_nibble(char n)
|
||||
{
|
||||
if (n >= '0' && n <= '9')
|
||||
return n - '0';
|
||||
|
||||
if (n >= 'A' && n <= 'F')
|
||||
return n - 'A' + 10;
|
||||
|
||||
if (n >= 'a' && n <= 'f')
|
||||
return n - 'a' + 10;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int __init qnap_tsx09_parse_hex_byte(const char *b)
|
||||
{
|
||||
int hi;
|
||||
int lo;
|
||||
|
||||
hi = qnap_tsx09_parse_hex_nibble(b[0]);
|
||||
lo = qnap_tsx09_parse_hex_nibble(b[1]);
|
||||
|
||||
if (hi < 0 || lo < 0)
|
||||
return -1;
|
||||
|
||||
return (hi << 4) | lo;
|
||||
}
|
||||
|
||||
static int __init qnap_tsx09_check_mac_addr(const char *addr_str)
|
||||
{
|
||||
u_int8_t addr[6];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
int byte;
|
||||
|
||||
/*
|
||||
* Enforce "xx:xx:xx:xx:xx:xx\n" format.
|
||||
*/
|
||||
if (addr_str[(i * 3) + 2] != ((i < 5) ? ':' : '\n'))
|
||||
return -1;
|
||||
|
||||
byte = qnap_tsx09_parse_hex_byte(addr_str + (i * 3));
|
||||
if (byte < 0)
|
||||
return -1;
|
||||
addr[i] = byte;
|
||||
}
|
||||
if (!mac_pton(addr_str, addr))
|
||||
return -1;
|
||||
|
||||
printk(KERN_INFO "tsx09: found ethernet mac address %pM\n", addr);
|
||||
|
||||
|
|
@ -118,12 +77,12 @@ void __init qnap_tsx09_find_mac_addr(u32 mem_base, u32 size)
|
|||
unsigned long addr;
|
||||
|
||||
for (addr = mem_base; addr < (mem_base + size); addr += 1024) {
|
||||
char *nor_page;
|
||||
void __iomem *nor_page;
|
||||
int ret = 0;
|
||||
|
||||
nor_page = ioremap(addr, 1024);
|
||||
if (nor_page != NULL) {
|
||||
ret = qnap_tsx09_check_mac_addr(nor_page);
|
||||
ret = qnap_tsx09_check_mac_addr((__force const char *)nor_page);
|
||||
iounmap(nor_page);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/pwm_backlight.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/leds.h>
|
||||
|
|
@ -469,6 +470,11 @@ static struct s3c24xx_mci_pdata h1940_mmc_cfg __initdata = {
|
|||
.ocr_avail = MMC_VDD_32_33,
|
||||
};
|
||||
|
||||
static struct pwm_lookup h1940_pwm_lookup[] = {
|
||||
PWM_LOOKUP("samsung-pwm", 0, "pwm-backlight", NULL, 36296,
|
||||
PWM_POLARITY_NORMAL),
|
||||
};
|
||||
|
||||
static int h1940_backlight_init(struct device *dev)
|
||||
{
|
||||
gpio_request(S3C2410_GPB(0), "Backlight");
|
||||
|
|
@ -503,11 +509,8 @@ static void h1940_backlight_exit(struct device *dev)
|
|||
|
||||
|
||||
static struct platform_pwm_backlight_data backlight_data = {
|
||||
.pwm_id = 0,
|
||||
.max_brightness = 100,
|
||||
.dft_brightness = 50,
|
||||
/* tcnt = 0x31 */
|
||||
.pwm_period_ns = 36296,
|
||||
.enable_gpio = -1,
|
||||
.init = h1940_backlight_init,
|
||||
.notify = h1940_backlight_notify,
|
||||
|
|
@ -725,6 +728,7 @@ static void __init h1940_init(void)
|
|||
gpio_request(H1940_LATCH_SD_POWER, "SD power");
|
||||
gpio_direction_output(H1940_LATCH_SD_POWER, 0);
|
||||
|
||||
pwm_add_table(h1940_pwm_lookup, ARRAY_SIZE(h1940_pwm_lookup));
|
||||
platform_add_devices(h1940_devices, ARRAY_SIZE(h1940_devices));
|
||||
|
||||
gpio_request(S3C2410_GPA(1), "Red LED blink");
|
||||
|
|
|
|||
|
|
@ -375,6 +375,11 @@ static struct s3c2410fb_mach_info rx1950_lcd_cfg = {
|
|||
|
||||
};
|
||||
|
||||
static struct pwm_lookup rx1950_pwm_lookup[] = {
|
||||
PWM_LOOKUP("samsung-pwm", 0, "pwm-backlight.0", NULL, 48000,
|
||||
PWM_POLARITY_NORMAL),
|
||||
};
|
||||
|
||||
static struct pwm_device *lcd_pwm;
|
||||
|
||||
static void rx1950_lcd_power(int enable)
|
||||
|
|
@ -520,10 +525,8 @@ static int rx1950_backlight_notify(struct device *dev, int brightness)
|
|||
}
|
||||
|
||||
static struct platform_pwm_backlight_data rx1950_backlight_data = {
|
||||
.pwm_id = 0,
|
||||
.max_brightness = 24,
|
||||
.dft_brightness = 4,
|
||||
.pwm_period_ns = 48000,
|
||||
.enable_gpio = -1,
|
||||
.init = rx1950_backlight_init,
|
||||
.notify = rx1950_backlight_notify,
|
||||
|
|
@ -792,6 +795,7 @@ static void __init rx1950_init_machine(void)
|
|||
gpio_direction_output(S3C2410_GPA(4), 0);
|
||||
gpio_direction_output(S3C2410_GPJ(6), 0);
|
||||
|
||||
pwm_add_table(rx1950_pwm_lookup, ARRAY_SIZE(rx1950_pwm_lookup));
|
||||
platform_add_devices(rx1950_devices, ARRAY_SIZE(rx1950_devices));
|
||||
|
||||
i2c_register_board_info(0, rx1950_i2c_devices,
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ static struct samsung_bl_drvdata samsung_dfl_bl_data __initdata = {
|
|||
.plat_data = {
|
||||
.max_brightness = 255,
|
||||
.dft_brightness = 255,
|
||||
.pwm_period_ns = 78770,
|
||||
.enable_gpio = -1,
|
||||
.init = samsung_bl_init,
|
||||
.exit = samsung_bl_exit,
|
||||
|
|
@ -111,7 +110,6 @@ void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
|
|||
samsung_bl_data = &samsung_bl_drvdata->plat_data;
|
||||
|
||||
/* Copy board specific data provided by user */
|
||||
samsung_bl_data->pwm_id = bl_data->pwm_id;
|
||||
samsung_bl_device->dev.parent = &samsung_device_pwm.dev;
|
||||
|
||||
if (bl_data->max_brightness)
|
||||
|
|
@ -120,8 +118,6 @@ void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
|
|||
samsung_bl_data->dft_brightness = bl_data->dft_brightness;
|
||||
if (bl_data->lth_brightness)
|
||||
samsung_bl_data->lth_brightness = bl_data->lth_brightness;
|
||||
if (bl_data->pwm_period_ns)
|
||||
samsung_bl_data->pwm_period_ns = bl_data->pwm_period_ns;
|
||||
if (bl_data->enable_gpio >= 0)
|
||||
samsung_bl_data->enable_gpio = bl_data->enable_gpio;
|
||||
if (bl_data->init)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/mmc/host.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/regulator/fixed.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/pwm_backlight.h>
|
||||
#include <linux/dm9000.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
|
|
@ -108,11 +109,14 @@ static struct s3c2410_uartcfg crag6410_uartcfgs[] __initdata = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct pwm_lookup crag6410_pwm_lookup[] = {
|
||||
PWM_LOOKUP("samsung-pwm", 0, "pwm-backlight", NULL, 100000,
|
||||
PWM_POLARITY_NORMAL),
|
||||
};
|
||||
|
||||
static struct platform_pwm_backlight_data crag6410_backlight_data = {
|
||||
.pwm_id = 0,
|
||||
.max_brightness = 1000,
|
||||
.dft_brightness = 600,
|
||||
.pwm_period_ns = 100000, /* about 1kHz */
|
||||
.enable_gpio = -1,
|
||||
};
|
||||
|
||||
|
|
@ -843,6 +847,7 @@ static void __init crag6410_machine_init(void)
|
|||
samsung_keypad_set_platdata(&crag6410_keypad_data);
|
||||
s3c64xx_spi0_set_platdata(NULL, 0, 2);
|
||||
|
||||
pwm_add_table(crag6410_pwm_lookup, ARRAY_SIZE(crag6410_pwm_lookup));
|
||||
platform_add_devices(crag6410_devices, ARRAY_SIZE(crag6410_devices));
|
||||
|
||||
gpio_led_register_device(-1, &gpio_leds_pdata);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/pwm_backlight.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
|
|
@ -73,6 +74,11 @@ static struct s3c2410_uartcfg hmt_uartcfgs[] __initdata = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct pwm_lookup hmt_pwm_lookup[] = {
|
||||
PWM_LOOKUP("samsung-pwm", 1, "pwm-backlight.0", NULL,
|
||||
1000000000 / (100 * 256 * 20), PWM_POLARITY_NORMAL),
|
||||
};
|
||||
|
||||
static int hmt_bl_init(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -110,10 +116,8 @@ static void hmt_bl_exit(struct device *dev)
|
|||
}
|
||||
|
||||
static struct platform_pwm_backlight_data hmt_backlight_data = {
|
||||
.pwm_id = 1,
|
||||
.max_brightness = 100 * 256,
|
||||
.dft_brightness = 40 * 256,
|
||||
.pwm_period_ns = 1000000000 / (100 * 256 * 20),
|
||||
.enable_gpio = -1,
|
||||
.init = hmt_bl_init,
|
||||
.notify = hmt_bl_notify,
|
||||
|
|
@ -268,6 +272,7 @@ static void __init hmt_machine_init(void)
|
|||
gpio_request(S3C64XX_GPF(13), "usb power");
|
||||
gpio_direction_output(S3C64XX_GPF(13), 1);
|
||||
|
||||
pwm_add_table(hmt_pwm_lookup, ARRAY_SIZE(hmt_pwm_lookup));
|
||||
platform_add_devices(hmt_devices, ARRAY_SIZE(hmt_devices));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/pwm_backlight.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial_s3c.h>
|
||||
|
|
@ -139,6 +140,11 @@ static struct platform_device smartq_usb_otg_vbus_dev = {
|
|||
.dev.platform_data = &smartq_usb_otg_vbus_pdata,
|
||||
};
|
||||
|
||||
static struct pwm_lookup smartq_pwm_lookup[] = {
|
||||
PWM_LOOKUP("samsung-pwm", 1, "pwm-backlight.0", NULL,
|
||||
1000000000 / (1000 * 20), PWM_POLARITY_NORMAL),
|
||||
};
|
||||
|
||||
static int smartq_bl_init(struct device *dev)
|
||||
{
|
||||
s3c_gpio_cfgpin(S3C64XX_GPF(15), S3C_GPIO_SFN(2));
|
||||
|
|
@ -147,10 +153,8 @@ static int smartq_bl_init(struct device *dev)
|
|||
}
|
||||
|
||||
static struct platform_pwm_backlight_data smartq_backlight_data = {
|
||||
.pwm_id = 1,
|
||||
.max_brightness = 1000,
|
||||
.dft_brightness = 600,
|
||||
.pwm_period_ns = 1000000000 / (1000 * 20),
|
||||
.enable_gpio = -1,
|
||||
.init = smartq_bl_init,
|
||||
};
|
||||
|
|
@ -396,5 +400,6 @@ void __init smartq_machine_init(void)
|
|||
WARN_ON(smartq_usb_host_init());
|
||||
WARN_ON(smartq_wifi_init());
|
||||
|
||||
pwm_add_table(smartq_pwm_lookup, ARRAY_SIZE(smartq_pwm_lookup));
|
||||
platform_add_devices(smartq_devices, ARRAY_SIZE(smartq_devices));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/smsc911x.h>
|
||||
#include <linux/regulator/fixed.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/pwm_backlight.h>
|
||||
#include <linux/platform_data/s3c-hsotg.h>
|
||||
|
||||
|
|
@ -623,8 +624,12 @@ static struct samsung_bl_gpio_info smdk6410_bl_gpio_info = {
|
|||
.func = S3C_GPIO_SFN(2),
|
||||
};
|
||||
|
||||
static struct pwm_lookup smdk6410_pwm_lookup[] = {
|
||||
PWM_LOOKUP("samsung-pwm", 1, "pwm-backlight.0", NULL, 78770,
|
||||
PWM_POLARITY_NORMAL),
|
||||
};
|
||||
|
||||
static struct platform_pwm_backlight_data smdk6410_bl_data = {
|
||||
.pwm_id = 1,
|
||||
.enable_gpio = -1,
|
||||
};
|
||||
|
||||
|
|
@ -695,6 +700,7 @@ static void __init smdk6410_machine_init(void)
|
|||
|
||||
platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));
|
||||
|
||||
pwm_add_table(smdk6410_pwm_lookup, ARRAY_SIZE(smdk6410_pwm_lookup));
|
||||
samsung_bl_set(&smdk6410_bl_gpio_info, &smdk6410_bl_data);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*/
|
||||
#include <linux/clk/shmobile.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
|
|
@ -124,36 +125,6 @@ static bool rmobile_pd_active_wakeup(struct device *dev)
|
|||
return true;
|
||||
}
|
||||
|
||||
static int rmobile_pd_attach_dev(struct generic_pm_domain *domain,
|
||||
struct device *dev)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = pm_clk_create(dev);
|
||||
if (error) {
|
||||
dev_err(dev, "pm_clk_create failed %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = pm_clk_add(dev, NULL);
|
||||
if (error) {
|
||||
dev_err(dev, "pm_clk_add failed %d\n", error);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
pm_clk_destroy(dev);
|
||||
return error;
|
||||
}
|
||||
|
||||
static void rmobile_pd_detach_dev(struct generic_pm_domain *domain,
|
||||
struct device *dev)
|
||||
{
|
||||
pm_clk_destroy(dev);
|
||||
}
|
||||
|
||||
static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
|
||||
{
|
||||
struct generic_pm_domain *genpd = &rmobile_pd->genpd;
|
||||
|
|
@ -164,8 +135,8 @@ static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
|
|||
genpd->dev_ops.active_wakeup = rmobile_pd_active_wakeup;
|
||||
genpd->power_off = rmobile_pd_power_down;
|
||||
genpd->power_on = rmobile_pd_power_up;
|
||||
genpd->attach_dev = rmobile_pd_attach_dev;
|
||||
genpd->detach_dev = rmobile_pd_detach_dev;
|
||||
genpd->attach_dev = cpg_mstp_attach_dev;
|
||||
genpd->detach_dev = cpg_mstp_detach_dev;
|
||||
__rmobile_pd_power_up(rmobile_pd, false);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,10 +26,11 @@ static const char * const sunxi_board_dt_compat[] = {
|
|||
"allwinner,sun4i-a10",
|
||||
"allwinner,sun5i-a10s",
|
||||
"allwinner,sun5i-a13",
|
||||
"allwinner,sun5i-r8",
|
||||
NULL,
|
||||
};
|
||||
|
||||
DT_MACHINE_START(SUNXI_DT, "Allwinner A1X (Device Tree)")
|
||||
DT_MACHINE_START(SUNXI_DT, "Allwinner sun4i/sun5i Families")
|
||||
.dt_compat = sunxi_board_dt_compat,
|
||||
.init_late = sunxi_dt_cpufreq_init,
|
||||
MACHINE_END
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ static struct platform_device wifi_rfkill_device = {
|
|||
static struct gpiod_lookup_table wifi_gpio_lookup = {
|
||||
.dev_id = "rfkill_gpio",
|
||||
.table = {
|
||||
GPIO_LOOKUP_IDX("tegra-gpio", 25, NULL, 0, 0),
|
||||
GPIO_LOOKUP_IDX("tegra-gpio", 85, NULL, 1, 0),
|
||||
GPIO_LOOKUP("tegra-gpio", 25, "reset", 0),
|
||||
GPIO_LOOKUP("tegra-gpio", 85, "shutdown", 0),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
obj-y := uniphier.o
|
||||
obj-$(CONFIG_SMP) += platsmp.o
|
||||
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
|
||||
|
|
|
|||
43
arch/arm/mach-uniphier/headsmp.S
Normal file
43
arch/arm/mach-uniphier/headsmp.S
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/assembler.h>
|
||||
#include <asm/cp15.h>
|
||||
|
||||
ENTRY(uniphier_smp_trampoline)
|
||||
ARM_BE8(setend be) @ ensure we are in BE8 mode
|
||||
mrc p15, 0, r0, c0, c0, 5 @ MPIDR (Multiprocessor Affinity Reg)
|
||||
and r2, r0, #0x3 @ CPU ID
|
||||
ldr r1, uniphier_smp_trampoline_jump
|
||||
ldr r3, uniphier_smp_trampoline_poll_addr
|
||||
mrc p15, 0, r0, c1, c0, 0 @ SCTLR (System Control Register)
|
||||
orr r0, r0, #CR_I @ Enable ICache
|
||||
bic r0, r0, #(CR_C | CR_M) @ Disable MMU and Dcache
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
b 1f @ cache the following 5 instructions
|
||||
0: wfe
|
||||
1: ldr r0, [r3]
|
||||
cmp r0, r2
|
||||
bxeq r1 @ branch to secondary_startup
|
||||
b 0b
|
||||
.globl uniphier_smp_trampoline_jump
|
||||
uniphier_smp_trampoline_jump:
|
||||
.word 0 @ set virt_to_phys(secondary_startup)
|
||||
.globl uniphier_smp_trampoline_poll_addr
|
||||
uniphier_smp_trampoline_poll_addr:
|
||||
.word 0 @ set CPU ID to be kicked to this reg
|
||||
.globl uniphier_smp_trampoline_end
|
||||
uniphier_smp_trampoline_end:
|
||||
ENDPROC(uniphier_smp_trampoline)
|
||||
|
|
@ -12,73 +12,198 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/compiler.h>
|
||||
#define pr_fmt(fmt) "uniphier: " fmt
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/hardware/cache-uniphier.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/smp.h>
|
||||
#include <asm/smp_scu.h>
|
||||
|
||||
static struct regmap *sbcm_regmap;
|
||||
/*
|
||||
* The secondary CPUs check this register from the boot ROM for the jump
|
||||
* destination. After that, it can be reused as a scratch register.
|
||||
*/
|
||||
#define UNIPHIER_SBC_ROM_BOOT_RSV2 0x1208
|
||||
|
||||
static void __init uniphier_smp_prepare_cpus(unsigned int max_cpus)
|
||||
static void __iomem *uniphier_smp_rom_boot_rsv2;
|
||||
static unsigned int uniphier_smp_max_cpus;
|
||||
|
||||
extern char uniphier_smp_trampoline;
|
||||
extern char uniphier_smp_trampoline_jump;
|
||||
extern char uniphier_smp_trampoline_poll_addr;
|
||||
extern char uniphier_smp_trampoline_end;
|
||||
|
||||
/*
|
||||
* Copy trampoline code to the tail of the 1st section of the page table used
|
||||
* in the boot ROM. This area is directly accessible by the secondary CPUs
|
||||
* for all the UniPhier SoCs.
|
||||
*/
|
||||
static const phys_addr_t uniphier_smp_trampoline_dest_end = SECTION_SIZE;
|
||||
static phys_addr_t uniphier_smp_trampoline_dest;
|
||||
|
||||
static int __init uniphier_smp_copy_trampoline(phys_addr_t poll_addr)
|
||||
{
|
||||
size_t trmp_size;
|
||||
static void __iomem *trmp_base;
|
||||
|
||||
if (!uniphier_cache_l2_is_enabled()) {
|
||||
pr_warn("outer cache is needed for SMP, but not enabled\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
uniphier_cache_l2_set_locked_ways(1);
|
||||
|
||||
outer_flush_all();
|
||||
|
||||
trmp_size = &uniphier_smp_trampoline_end - &uniphier_smp_trampoline;
|
||||
uniphier_smp_trampoline_dest = uniphier_smp_trampoline_dest_end -
|
||||
trmp_size;
|
||||
|
||||
uniphier_cache_l2_touch_range(uniphier_smp_trampoline_dest,
|
||||
uniphier_smp_trampoline_dest_end);
|
||||
|
||||
trmp_base = ioremap_cache(uniphier_smp_trampoline_dest, trmp_size);
|
||||
if (!trmp_base) {
|
||||
pr_err("failed to map trampoline destination area\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(trmp_base, &uniphier_smp_trampoline, trmp_size);
|
||||
|
||||
writel(virt_to_phys(secondary_startup),
|
||||
trmp_base + (&uniphier_smp_trampoline_jump -
|
||||
&uniphier_smp_trampoline));
|
||||
|
||||
writel(poll_addr, trmp_base + (&uniphier_smp_trampoline_poll_addr -
|
||||
&uniphier_smp_trampoline));
|
||||
|
||||
flush_cache_all(); /* flush out trampoline code to outer cache */
|
||||
|
||||
iounmap(trmp_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init uniphier_smp_prepare_trampoline(unsigned int max_cpus)
|
||||
{
|
||||
struct device_node *np;
|
||||
struct resource res;
|
||||
phys_addr_t rom_rsv2_phys;
|
||||
int ret;
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL,
|
||||
"socionext,uniphier-system-bus-controller");
|
||||
ret = of_address_to_resource(np, 1, &res);
|
||||
if (ret) {
|
||||
pr_err("failed to get resource of system-bus-controller\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
rom_rsv2_phys = res.start + UNIPHIER_SBC_ROM_BOOT_RSV2;
|
||||
|
||||
ret = uniphier_smp_copy_trampoline(rom_rsv2_phys);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
uniphier_smp_rom_boot_rsv2 = ioremap(rom_rsv2_phys, sizeof(SZ_4));
|
||||
if (!uniphier_smp_rom_boot_rsv2) {
|
||||
pr_err("failed to map ROM_BOOT_RSV2 register\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
writel(uniphier_smp_trampoline_dest, uniphier_smp_rom_boot_rsv2);
|
||||
asm("sev"); /* Bring up all secondary CPUs to the trampoline code */
|
||||
|
||||
uniphier_smp_max_cpus = max_cpus; /* save for later use */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init uniphier_smp_unprepare_trampoline(void)
|
||||
{
|
||||
iounmap(uniphier_smp_rom_boot_rsv2);
|
||||
|
||||
if (uniphier_smp_trampoline_dest)
|
||||
outer_inv_range(uniphier_smp_trampoline_dest,
|
||||
uniphier_smp_trampoline_dest_end);
|
||||
|
||||
uniphier_cache_l2_set_locked_ways(0);
|
||||
}
|
||||
|
||||
static int __init uniphier_smp_enable_scu(void)
|
||||
{
|
||||
static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
|
||||
unsigned long scu_base_phys = 0;
|
||||
void __iomem *scu_base;
|
||||
|
||||
sbcm_regmap = syscon_regmap_lookup_by_compatible(
|
||||
"socionext,uniphier-system-bus-controller-misc");
|
||||
if (IS_ERR(sbcm_regmap)) {
|
||||
pr_err("failed to regmap system-bus-controller-misc\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (scu_a9_has_base())
|
||||
scu_base_phys = scu_a9_get_base();
|
||||
|
||||
if (!scu_base_phys) {
|
||||
pr_err("failed to get scu base\n");
|
||||
goto err;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
scu_base = ioremap(scu_base_phys, SZ_128);
|
||||
if (!scu_base) {
|
||||
pr_err("failed to remap scu base (0x%08lx)\n", scu_base_phys);
|
||||
goto err;
|
||||
pr_err("failed to map scu base\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
scu_enable(scu_base);
|
||||
iounmap(scu_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init uniphier_smp_prepare_cpus(unsigned int max_cpus)
|
||||
{
|
||||
static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
|
||||
int ret;
|
||||
|
||||
ret = uniphier_smp_prepare_trampoline(max_cpus);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = uniphier_smp_enable_scu();
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return;
|
||||
err:
|
||||
pr_warn("disabling SMP\n");
|
||||
init_cpu_present(&only_cpu_0);
|
||||
sbcm_regmap = NULL;
|
||||
uniphier_smp_unprepare_trampoline();
|
||||
}
|
||||
|
||||
static int uniphier_boot_secondary(unsigned int cpu,
|
||||
struct task_struct *idle)
|
||||
static int __init uniphier_smp_boot_secondary(unsigned int cpu,
|
||||
struct task_struct *idle)
|
||||
{
|
||||
int ret;
|
||||
if (WARN_ON_ONCE(!uniphier_smp_rom_boot_rsv2))
|
||||
return -EFAULT;
|
||||
|
||||
if (!sbcm_regmap)
|
||||
return -ENODEV;
|
||||
writel(cpu, uniphier_smp_rom_boot_rsv2);
|
||||
readl(uniphier_smp_rom_boot_rsv2); /* relax */
|
||||
|
||||
ret = regmap_write(sbcm_regmap, 0x1208,
|
||||
virt_to_phys(secondary_startup));
|
||||
if (!ret)
|
||||
asm("sev"); /* wake up secondary CPU */
|
||||
asm("sev"); /* wake up secondary CPUs sleeping in the trampoline */
|
||||
|
||||
return ret;
|
||||
if (cpu == uniphier_smp_max_cpus - 1) {
|
||||
/* clean up resources if this is the last CPU */
|
||||
uniphier_smp_unprepare_trampoline();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct smp_operations uniphier_smp_ops __initdata = {
|
||||
static struct smp_operations uniphier_smp_ops __initdata = {
|
||||
.smp_prepare_cpus = uniphier_smp_prepare_cpus,
|
||||
.smp_boot_secondary = uniphier_boot_secondary,
|
||||
.smp_boot_secondary = uniphier_smp_boot_secondary,
|
||||
};
|
||||
CPU_METHOD_OF_DECLARE(uniphier_smp, "socionext,uniphier-smp",
|
||||
&uniphier_smp_ops);
|
||||
|
|
|
|||
|
|
@ -974,6 +974,16 @@ config CACHE_TAUROS2
|
|||
This option enables the Tauros2 L2 cache controller (as
|
||||
found on PJ1/PJ4).
|
||||
|
||||
config CACHE_UNIPHIER
|
||||
bool "Enable the UniPhier outer cache controller"
|
||||
depends on ARCH_UNIPHIER
|
||||
default y
|
||||
select OUTER_CACHE
|
||||
select OUTER_CACHE_SYNC
|
||||
help
|
||||
This option enables the UniPhier outer cache (system cache)
|
||||
controller.
|
||||
|
||||
config CACHE_XSC3L2
|
||||
bool "Enable the L2 cache on XScale3"
|
||||
depends on CPU_XSC3
|
||||
|
|
|
|||
|
|
@ -103,3 +103,4 @@ obj-$(CONFIG_CACHE_FEROCEON_L2) += cache-feroceon-l2.o
|
|||
obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o l2c-l2x0-resume.o
|
||||
obj-$(CONFIG_CACHE_XSC3L2) += cache-xsc3l2.o
|
||||
obj-$(CONFIG_CACHE_TAUROS2) += cache-tauros2.o
|
||||
obj-$(CONFIG_CACHE_UNIPHIER) += cache-uniphier.o
|
||||
|
|
|
|||
555
arch/arm/mm/cache-uniphier.c
Normal file
555
arch/arm/mm/cache-uniphier.c
Normal file
|
|
@ -0,0 +1,555 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "uniphier: " fmt
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/hardware/cache-uniphier.h>
|
||||
#include <asm/outercache.h>
|
||||
|
||||
/* control registers */
|
||||
#define UNIPHIER_SSCC 0x0 /* Control Register */
|
||||
#define UNIPHIER_SSCC_BST BIT(20) /* UCWG burst read */
|
||||
#define UNIPHIER_SSCC_ACT BIT(19) /* Inst-Data separate */
|
||||
#define UNIPHIER_SSCC_WTG BIT(18) /* WT gathering on */
|
||||
#define UNIPHIER_SSCC_PRD BIT(17) /* enable pre-fetch */
|
||||
#define UNIPHIER_SSCC_ON BIT(0) /* enable cache */
|
||||
#define UNIPHIER_SSCLPDAWCR 0x30 /* Unified/Data Active Way Control */
|
||||
#define UNIPHIER_SSCLPIAWCR 0x34 /* Instruction Active Way Control */
|
||||
|
||||
/* revision registers */
|
||||
#define UNIPHIER_SSCID 0x0 /* ID Register */
|
||||
|
||||
/* operation registers */
|
||||
#define UNIPHIER_SSCOPE 0x244 /* Cache Operation Primitive Entry */
|
||||
#define UNIPHIER_SSCOPE_CM_INV 0x0 /* invalidate */
|
||||
#define UNIPHIER_SSCOPE_CM_CLEAN 0x1 /* clean */
|
||||
#define UNIPHIER_SSCOPE_CM_FLUSH 0x2 /* flush */
|
||||
#define UNIPHIER_SSCOPE_CM_SYNC 0x8 /* sync (drain bufs) */
|
||||
#define UNIPHIER_SSCOPE_CM_FLUSH_PREFETCH 0x9 /* flush p-fetch buf */
|
||||
#define UNIPHIER_SSCOQM 0x248 /* Cache Operation Queue Mode */
|
||||
#define UNIPHIER_SSCOQM_TID_MASK (0x3 << 21)
|
||||
#define UNIPHIER_SSCOQM_TID_LRU_DATA (0x0 << 21)
|
||||
#define UNIPHIER_SSCOQM_TID_LRU_INST (0x1 << 21)
|
||||
#define UNIPHIER_SSCOQM_TID_WAY (0x2 << 21)
|
||||
#define UNIPHIER_SSCOQM_S_MASK (0x3 << 17)
|
||||
#define UNIPHIER_SSCOQM_S_RANGE (0x0 << 17)
|
||||
#define UNIPHIER_SSCOQM_S_ALL (0x1 << 17)
|
||||
#define UNIPHIER_SSCOQM_S_WAY (0x2 << 17)
|
||||
#define UNIPHIER_SSCOQM_CE BIT(15) /* notify completion */
|
||||
#define UNIPHIER_SSCOQM_CM_INV 0x0 /* invalidate */
|
||||
#define UNIPHIER_SSCOQM_CM_CLEAN 0x1 /* clean */
|
||||
#define UNIPHIER_SSCOQM_CM_FLUSH 0x2 /* flush */
|
||||
#define UNIPHIER_SSCOQM_CM_PREFETCH 0x3 /* prefetch to cache */
|
||||
#define UNIPHIER_SSCOQM_CM_PREFETCH_BUF 0x4 /* prefetch to pf-buf */
|
||||
#define UNIPHIER_SSCOQM_CM_TOUCH 0x5 /* touch */
|
||||
#define UNIPHIER_SSCOQM_CM_TOUCH_ZERO 0x6 /* touch to zero */
|
||||
#define UNIPHIER_SSCOQM_CM_TOUCH_DIRTY 0x7 /* touch with dirty */
|
||||
#define UNIPHIER_SSCOQAD 0x24c /* Cache Operation Queue Address */
|
||||
#define UNIPHIER_SSCOQSZ 0x250 /* Cache Operation Queue Size */
|
||||
#define UNIPHIER_SSCOQMASK 0x254 /* Cache Operation Queue Address Mask */
|
||||
#define UNIPHIER_SSCOQWN 0x258 /* Cache Operation Queue Way Number */
|
||||
#define UNIPHIER_SSCOPPQSEF 0x25c /* Cache Operation Queue Set Complete*/
|
||||
#define UNIPHIER_SSCOPPQSEF_FE BIT(1)
|
||||
#define UNIPHIER_SSCOPPQSEF_OE BIT(0)
|
||||
#define UNIPHIER_SSCOLPQS 0x260 /* Cache Operation Queue Status */
|
||||
#define UNIPHIER_SSCOLPQS_EF BIT(2)
|
||||
#define UNIPHIER_SSCOLPQS_EST BIT(1)
|
||||
#define UNIPHIER_SSCOLPQS_QST BIT(0)
|
||||
|
||||
/* Is the touch/pre-fetch destination specified by ways? */
|
||||
#define UNIPHIER_SSCOQM_TID_IS_WAY(op) \
|
||||
((op & UNIPHIER_SSCOQM_TID_MASK) == UNIPHIER_SSCOQM_TID_WAY)
|
||||
/* Is the operation region specified by address range? */
|
||||
#define UNIPHIER_SSCOQM_S_IS_RANGE(op) \
|
||||
((op & UNIPHIER_SSCOQM_S_MASK) == UNIPHIER_SSCOQM_S_RANGE)
|
||||
|
||||
/**
|
||||
* uniphier_cache_data - UniPhier outer cache specific data
|
||||
*
|
||||
* @ctrl_base: virtual base address of control registers
|
||||
* @rev_base: virtual base address of revision registers
|
||||
* @op_base: virtual base address of operation registers
|
||||
* @way_present_mask: each bit specifies if the way is present
|
||||
* @way_locked_mask: each bit specifies if the way is locked
|
||||
* @nsets: number of associativity sets
|
||||
* @line_size: line size in bytes
|
||||
* @range_op_max_size: max size that can be handled by a single range operation
|
||||
* @list: list node to include this level in the whole cache hierarchy
|
||||
*/
|
||||
struct uniphier_cache_data {
|
||||
void __iomem *ctrl_base;
|
||||
void __iomem *rev_base;
|
||||
void __iomem *op_base;
|
||||
u32 way_present_mask;
|
||||
u32 way_locked_mask;
|
||||
u32 nsets;
|
||||
u32 line_size;
|
||||
u32 range_op_max_size;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
/*
|
||||
* List of the whole outer cache hierarchy. This list is only modified during
|
||||
* the early boot stage, so no mutex is taken for the access to the list.
|
||||
*/
|
||||
static LIST_HEAD(uniphier_cache_list);
|
||||
|
||||
/**
|
||||
* __uniphier_cache_sync - perform a sync point for a particular cache level
|
||||
*
|
||||
* @data: cache controller specific data
|
||||
*/
|
||||
static void __uniphier_cache_sync(struct uniphier_cache_data *data)
|
||||
{
|
||||
/* This sequence need not be atomic. Do not disable IRQ. */
|
||||
writel_relaxed(UNIPHIER_SSCOPE_CM_SYNC,
|
||||
data->op_base + UNIPHIER_SSCOPE);
|
||||
/* need a read back to confirm */
|
||||
readl_relaxed(data->op_base + UNIPHIER_SSCOPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* __uniphier_cache_maint_common - run a queue operation for a particular level
|
||||
*
|
||||
* @data: cache controller specific data
|
||||
* @start: start address of range operation (don't care for "all" operation)
|
||||
* @size: data size of range operation (don't care for "all" operation)
|
||||
* @operation: flags to specify the desired cache operation
|
||||
*/
|
||||
static void __uniphier_cache_maint_common(struct uniphier_cache_data *data,
|
||||
unsigned long start,
|
||||
unsigned long size,
|
||||
u32 operation)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* No spin lock is necessary here because:
|
||||
*
|
||||
* [1] This outer cache controller is able to accept maintenance
|
||||
* operations from multiple CPUs at a time in an SMP system; if a
|
||||
* maintenance operation is under way and another operation is issued,
|
||||
* the new one is stored in the queue. The controller performs one
|
||||
* operation after another. If the queue is full, the status register,
|
||||
* UNIPHIER_SSCOPPQSEF, indicates that the queue registration has
|
||||
* failed. The status registers, UNIPHIER_{SSCOPPQSEF, SSCOLPQS}, have
|
||||
* different instances for each CPU, i.e. each CPU can track the status
|
||||
* of the maintenance operations triggered by itself.
|
||||
*
|
||||
* [2] The cache command registers, UNIPHIER_{SSCOQM, SSCOQAD, SSCOQSZ,
|
||||
* SSCOQWN}, are shared between multiple CPUs, but the hardware still
|
||||
* guarantees the registration sequence is atomic; the write access to
|
||||
* them are arbitrated by the hardware. The first accessor to the
|
||||
* register, UNIPHIER_SSCOQM, holds the access right and it is released
|
||||
* by reading the status register, UNIPHIER_SSCOPPQSEF. While one CPU
|
||||
* is holding the access right, other CPUs fail to register operations.
|
||||
* One CPU should not hold the access right for a long time, so local
|
||||
* IRQs should be disabled while the following sequence.
|
||||
*/
|
||||
local_irq_save(flags);
|
||||
|
||||
/* clear the complete notification flag */
|
||||
writel_relaxed(UNIPHIER_SSCOLPQS_EF, data->op_base + UNIPHIER_SSCOLPQS);
|
||||
|
||||
do {
|
||||
/* set cache operation */
|
||||
writel_relaxed(UNIPHIER_SSCOQM_CE | operation,
|
||||
data->op_base + UNIPHIER_SSCOQM);
|
||||
|
||||
/* set address range if needed */
|
||||
if (likely(UNIPHIER_SSCOQM_S_IS_RANGE(operation))) {
|
||||
writel_relaxed(start, data->op_base + UNIPHIER_SSCOQAD);
|
||||
writel_relaxed(size, data->op_base + UNIPHIER_SSCOQSZ);
|
||||
}
|
||||
|
||||
/* set target ways if needed */
|
||||
if (unlikely(UNIPHIER_SSCOQM_TID_IS_WAY(operation)))
|
||||
writel_relaxed(data->way_locked_mask,
|
||||
data->op_base + UNIPHIER_SSCOQWN);
|
||||
} while (unlikely(readl_relaxed(data->op_base + UNIPHIER_SSCOPPQSEF) &
|
||||
(UNIPHIER_SSCOPPQSEF_FE | UNIPHIER_SSCOPPQSEF_OE)));
|
||||
|
||||
/* wait until the operation is completed */
|
||||
while (likely(readl_relaxed(data->op_base + UNIPHIER_SSCOLPQS) !=
|
||||
UNIPHIER_SSCOLPQS_EF))
|
||||
cpu_relax();
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static void __uniphier_cache_maint_all(struct uniphier_cache_data *data,
|
||||
u32 operation)
|
||||
{
|
||||
__uniphier_cache_maint_common(data, 0, 0,
|
||||
UNIPHIER_SSCOQM_S_ALL | operation);
|
||||
|
||||
__uniphier_cache_sync(data);
|
||||
}
|
||||
|
||||
static void __uniphier_cache_maint_range(struct uniphier_cache_data *data,
|
||||
unsigned long start, unsigned long end,
|
||||
u32 operation)
|
||||
{
|
||||
unsigned long size;
|
||||
|
||||
/*
|
||||
* If the start address is not aligned,
|
||||
* perform a cache operation for the first cache-line
|
||||
*/
|
||||
start = start & ~(data->line_size - 1);
|
||||
|
||||
size = end - start;
|
||||
|
||||
if (unlikely(size >= (unsigned long)(-data->line_size))) {
|
||||
/* this means cache operation for all range */
|
||||
__uniphier_cache_maint_all(data, operation);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the end address is not aligned,
|
||||
* perform a cache operation for the last cache-line
|
||||
*/
|
||||
size = ALIGN(size, data->line_size);
|
||||
|
||||
while (size) {
|
||||
unsigned long chunk_size = min_t(unsigned long, size,
|
||||
data->range_op_max_size);
|
||||
|
||||
__uniphier_cache_maint_common(data, start, chunk_size,
|
||||
UNIPHIER_SSCOQM_S_RANGE | operation);
|
||||
|
||||
start += chunk_size;
|
||||
size -= chunk_size;
|
||||
}
|
||||
|
||||
__uniphier_cache_sync(data);
|
||||
}
|
||||
|
||||
static void __uniphier_cache_enable(struct uniphier_cache_data *data, bool on)
|
||||
{
|
||||
u32 val = 0;
|
||||
|
||||
if (on)
|
||||
val = UNIPHIER_SSCC_WTG | UNIPHIER_SSCC_PRD | UNIPHIER_SSCC_ON;
|
||||
|
||||
writel_relaxed(val, data->ctrl_base + UNIPHIER_SSCC);
|
||||
}
|
||||
|
||||
static void __init __uniphier_cache_set_locked_ways(
|
||||
struct uniphier_cache_data *data,
|
||||
u32 way_mask)
|
||||
{
|
||||
data->way_locked_mask = way_mask & data->way_present_mask;
|
||||
|
||||
writel_relaxed(~data->way_locked_mask & data->way_present_mask,
|
||||
data->ctrl_base + UNIPHIER_SSCLPDAWCR);
|
||||
}
|
||||
|
||||
static void uniphier_cache_maint_range(unsigned long start, unsigned long end,
|
||||
u32 operation)
|
||||
{
|
||||
struct uniphier_cache_data *data;
|
||||
|
||||
list_for_each_entry(data, &uniphier_cache_list, list)
|
||||
__uniphier_cache_maint_range(data, start, end, operation);
|
||||
}
|
||||
|
||||
static void uniphier_cache_maint_all(u32 operation)
|
||||
{
|
||||
struct uniphier_cache_data *data;
|
||||
|
||||
list_for_each_entry(data, &uniphier_cache_list, list)
|
||||
__uniphier_cache_maint_all(data, operation);
|
||||
}
|
||||
|
||||
static void uniphier_cache_inv_range(unsigned long start, unsigned long end)
|
||||
{
|
||||
uniphier_cache_maint_range(start, end, UNIPHIER_SSCOQM_CM_INV);
|
||||
}
|
||||
|
||||
static void uniphier_cache_clean_range(unsigned long start, unsigned long end)
|
||||
{
|
||||
uniphier_cache_maint_range(start, end, UNIPHIER_SSCOQM_CM_CLEAN);
|
||||
}
|
||||
|
||||
static void uniphier_cache_flush_range(unsigned long start, unsigned long end)
|
||||
{
|
||||
uniphier_cache_maint_range(start, end, UNIPHIER_SSCOQM_CM_FLUSH);
|
||||
}
|
||||
|
||||
static void __init uniphier_cache_inv_all(void)
|
||||
{
|
||||
uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_INV);
|
||||
}
|
||||
|
||||
static void uniphier_cache_flush_all(void)
|
||||
{
|
||||
uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_FLUSH);
|
||||
}
|
||||
|
||||
static void uniphier_cache_disable(void)
|
||||
{
|
||||
struct uniphier_cache_data *data;
|
||||
|
||||
list_for_each_entry_reverse(data, &uniphier_cache_list, list)
|
||||
__uniphier_cache_enable(data, false);
|
||||
|
||||
uniphier_cache_flush_all();
|
||||
}
|
||||
|
||||
static void __init uniphier_cache_enable(void)
|
||||
{
|
||||
struct uniphier_cache_data *data;
|
||||
|
||||
uniphier_cache_inv_all();
|
||||
|
||||
list_for_each_entry(data, &uniphier_cache_list, list) {
|
||||
__uniphier_cache_enable(data, true);
|
||||
__uniphier_cache_set_locked_ways(data, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void uniphier_cache_sync(void)
|
||||
{
|
||||
struct uniphier_cache_data *data;
|
||||
|
||||
list_for_each_entry(data, &uniphier_cache_list, list)
|
||||
__uniphier_cache_sync(data);
|
||||
}
|
||||
|
||||
int __init uniphier_cache_l2_is_enabled(void)
|
||||
{
|
||||
struct uniphier_cache_data *data;
|
||||
|
||||
data = list_first_entry_or_null(&uniphier_cache_list,
|
||||
struct uniphier_cache_data, list);
|
||||
if (!data)
|
||||
return 0;
|
||||
|
||||
return !!(readl_relaxed(data->ctrl_base + UNIPHIER_SSCC) &
|
||||
UNIPHIER_SSCC_ON);
|
||||
}
|
||||
|
||||
void __init uniphier_cache_l2_touch_range(unsigned long start,
|
||||
unsigned long end)
|
||||
{
|
||||
struct uniphier_cache_data *data;
|
||||
|
||||
data = list_first_entry_or_null(&uniphier_cache_list,
|
||||
struct uniphier_cache_data, list);
|
||||
if (data)
|
||||
__uniphier_cache_maint_range(data, start, end,
|
||||
UNIPHIER_SSCOQM_TID_WAY |
|
||||
UNIPHIER_SSCOQM_CM_TOUCH);
|
||||
}
|
||||
|
||||
void __init uniphier_cache_l2_set_locked_ways(u32 way_mask)
|
||||
{
|
||||
struct uniphier_cache_data *data;
|
||||
|
||||
data = list_first_entry_or_null(&uniphier_cache_list,
|
||||
struct uniphier_cache_data, list);
|
||||
if (data)
|
||||
__uniphier_cache_set_locked_ways(data, way_mask);
|
||||
}
|
||||
|
||||
static const struct of_device_id uniphier_cache_match[] __initconst = {
|
||||
{
|
||||
.compatible = "socionext,uniphier-system-cache",
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct device_node * __init uniphier_cache_get_next_level_node(
|
||||
struct device_node *np)
|
||||
{
|
||||
u32 phandle;
|
||||
|
||||
if (of_property_read_u32(np, "next-level-cache", &phandle))
|
||||
return NULL;
|
||||
|
||||
return of_find_node_by_phandle(phandle);
|
||||
}
|
||||
|
||||
static int __init __uniphier_cache_init(struct device_node *np,
|
||||
unsigned int *cache_level)
|
||||
{
|
||||
struct uniphier_cache_data *data;
|
||||
u32 level, cache_size;
|
||||
struct device_node *next_np;
|
||||
int ret = 0;
|
||||
|
||||
if (!of_match_node(uniphier_cache_match, np)) {
|
||||
pr_err("L%d: not compatible with uniphier cache\n",
|
||||
*cache_level);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(np, "cache-level", &level)) {
|
||||
pr_err("L%d: cache-level is not specified\n", *cache_level);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (level != *cache_level) {
|
||||
pr_err("L%d: cache-level is unexpected value %d\n",
|
||||
*cache_level, level);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!of_property_read_bool(np, "cache-unified")) {
|
||||
pr_err("L%d: cache-unified is not specified\n", *cache_level);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
if (of_property_read_u32(np, "cache-line-size", &data->line_size) ||
|
||||
!is_power_of_2(data->line_size)) {
|
||||
pr_err("L%d: cache-line-size is unspecified or invalid\n",
|
||||
*cache_level);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(np, "cache-sets", &data->nsets) ||
|
||||
!is_power_of_2(data->nsets)) {
|
||||
pr_err("L%d: cache-sets is unspecified or invalid\n",
|
||||
*cache_level);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(np, "cache-size", &cache_size) ||
|
||||
cache_size == 0 || cache_size % (data->nsets * data->line_size)) {
|
||||
pr_err("L%d: cache-size is unspecified or invalid\n",
|
||||
*cache_level);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
data->way_present_mask =
|
||||
((u32)1 << cache_size / data->nsets / data->line_size) - 1;
|
||||
|
||||
data->ctrl_base = of_iomap(np, 0);
|
||||
if (!data->ctrl_base) {
|
||||
pr_err("L%d: failed to map control register\n", *cache_level);
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
data->rev_base = of_iomap(np, 1);
|
||||
if (!data->rev_base) {
|
||||
pr_err("L%d: failed to map revision register\n", *cache_level);
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
data->op_base = of_iomap(np, 2);
|
||||
if (!data->op_base) {
|
||||
pr_err("L%d: failed to map operation register\n", *cache_level);
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (*cache_level == 2) {
|
||||
u32 revision = readl(data->rev_base + UNIPHIER_SSCID);
|
||||
/*
|
||||
* The size of range operation is limited to (1 << 22) or less
|
||||
* for PH-sLD8 or older SoCs.
|
||||
*/
|
||||
if (revision <= 0x16)
|
||||
data->range_op_max_size = (u32)1 << 22;
|
||||
}
|
||||
|
||||
data->range_op_max_size -= data->line_size;
|
||||
|
||||
INIT_LIST_HEAD(&data->list);
|
||||
list_add_tail(&data->list, &uniphier_cache_list); /* no mutex */
|
||||
|
||||
/*
|
||||
* OK, this level has been successfully initialized. Look for the next
|
||||
* level cache. Do not roll back even if the initialization of the
|
||||
* next level cache fails because we want to continue with available
|
||||
* cache levels.
|
||||
*/
|
||||
next_np = uniphier_cache_get_next_level_node(np);
|
||||
if (next_np) {
|
||||
(*cache_level)++;
|
||||
ret = __uniphier_cache_init(next_np, cache_level);
|
||||
}
|
||||
of_node_put(next_np);
|
||||
|
||||
return ret;
|
||||
err:
|
||||
iounmap(data->op_base);
|
||||
iounmap(data->rev_base);
|
||||
iounmap(data->ctrl_base);
|
||||
kfree(data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __init uniphier_cache_init(void)
|
||||
{
|
||||
struct device_node *np = NULL;
|
||||
unsigned int cache_level;
|
||||
int ret = 0;
|
||||
|
||||
/* look for level 2 cache */
|
||||
while ((np = of_find_matching_node(np, uniphier_cache_match)))
|
||||
if (!of_property_read_u32(np, "cache-level", &cache_level) &&
|
||||
cache_level == 2)
|
||||
break;
|
||||
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
ret = __uniphier_cache_init(np, &cache_level);
|
||||
of_node_put(np);
|
||||
|
||||
if (ret) {
|
||||
/*
|
||||
* Error out iif L2 initialization fails. Continue with any
|
||||
* error on L3 or outer because they are optional.
|
||||
*/
|
||||
if (cache_level == 2) {
|
||||
pr_err("failed to initialize L2 cache\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
cache_level--;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
outer_cache.inv_range = uniphier_cache_inv_range;
|
||||
outer_cache.clean_range = uniphier_cache_clean_range;
|
||||
outer_cache.flush_range = uniphier_cache_flush_range;
|
||||
outer_cache.flush_all = uniphier_cache_flush_all;
|
||||
outer_cache.disable = uniphier_cache_disable;
|
||||
outer_cache.sync = uniphier_cache_sync;
|
||||
|
||||
uniphier_cache_enable();
|
||||
|
||||
pr_info("enabled outer cache (cache level: %d)\n", cache_level);
|
||||
|
||||
return ret;
|
||||
}
|
||||
Loading…
Reference in a new issue