mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08: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
@ -19,7 +19,7 @@ executing kernel.
|
||||
Address: sysram_ns_base_addr
|
||||
Offset Value Purpose
|
||||
=============================================================================
|
||||
0x08 exynos_cpu_resume_ns System suspend
|
||||
0x08 exynos_cpu_resume_ns, mcpm_entry_point System suspend
|
||||
0x0c 0x00000bad (Magic cookie) System suspend
|
||||
0x1c exynos4_secondary_startup Secondary CPU boot
|
||||
0x1c + 4*cpu exynos4_secondary_startup (Exynos4412) Secondary CPU boot
|
||||
@ -56,7 +56,8 @@ Offset Value Purpose
|
||||
Address: pmu_base_addr
|
||||
Offset Value Purpose
|
||||
=============================================================================
|
||||
0x0908 Non-zero (only Exynos3250) Secondary CPU boot up indicator
|
||||
0x0908 Non-zero Secondary CPU boot up indicator
|
||||
on Exynos3250 and Exynos542x
|
||||
|
||||
|
||||
4. Glossary
|
||||
|
56
Documentation/arm/keystone/knav-qmss.txt
Normal file
56
Documentation/arm/keystone/knav-qmss.txt
Normal file
@ -0,0 +1,56 @@
|
||||
* Texas Instruments Keystone Navigator Queue Management SubSystem driver
|
||||
|
||||
Driver source code path
|
||||
drivers/soc/ti/knav_qmss.c
|
||||
drivers/soc/ti/knav_qmss_acc.c
|
||||
|
||||
The QMSS (Queue Manager Sub System) found on Keystone SOCs is one of
|
||||
the main hardware sub system which forms the backbone of the Keystone
|
||||
multi-core Navigator. QMSS consist of queue managers, packed-data structure
|
||||
processors(PDSP), linking RAM, descriptor pools and infrastructure
|
||||
Packet DMA.
|
||||
The Queue Manager is a hardware module that is responsible for accelerating
|
||||
management of the packet queues. Packets are queued/de-queued by writing or
|
||||
reading descriptor address to a particular memory mapped location. The PDSPs
|
||||
perform QMSS related functions like accumulation, QoS, or event management.
|
||||
Linking RAM registers are used to link the descriptors which are stored in
|
||||
descriptor RAM. Descriptor RAM is configurable as internal or external memory.
|
||||
The QMSS driver manages the PDSP setups, linking RAM regions,
|
||||
queue pool management (allocation, push, pop and notify) and descriptor
|
||||
pool management.
|
||||
|
||||
knav qmss driver provides a set of APIs to drivers to open/close qmss queues,
|
||||
allocate descriptor pools, map the descriptors, push/pop to queues etc. For
|
||||
details of the available APIs, please refers to include/linux/soc/ti/knav_qmss.h
|
||||
|
||||
DT documentation is available at
|
||||
Documentation/devicetree/bindings/soc/ti/keystone-navigator-qmss.txt
|
||||
|
||||
Accumulator QMSS queues using PDSP firmware
|
||||
============================================
|
||||
The QMSS PDSP firmware support accumulator channel that can monitor a single
|
||||
queue or multiple contiguous queues. drivers/soc/ti/knav_qmss_acc.c is the
|
||||
driver that interface with the accumulator PDSP. This configures
|
||||
accumulator channels defined in DTS (example in DT documentation) to monitor
|
||||
1 or 32 queues per channel. More description on the firmware is available in
|
||||
CPPI/QMSS Low Level Driver document (docs/CPPI_QMSS_LLD_SDS.pdf) at
|
||||
git://git.ti.com/keystone-rtos/qmss-lld.git
|
||||
|
||||
k2_qmss_pdsp_acc48_k2_le_1_0_0_9.bin firmware supports upto 48 accumulator
|
||||
channels. This firmware is available under ti-keystone folder of
|
||||
firmware.git at
|
||||
git://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git
|
||||
|
||||
To use copy the firmware image to lib/firmware folder of the initramfs or
|
||||
ubifs file system and provide a sym link to k2_qmss_pdsp_acc48_k2_le_1_0_0_9.bin
|
||||
in the file system and boot up the kernel. User would see
|
||||
|
||||
"firmware file ks2_qmss_pdsp_acc48.bin downloaded for PDSP"
|
||||
|
||||
in the boot up log if loading of firmware to PDSP is successful.
|
||||
|
||||
Use of accumulated queues requires the firmware image to be present in the
|
||||
file system. The driver doesn't acc queues to the supported queue range if
|
||||
PDSP is not running in the SoC. The API call fails if there is a queue open
|
||||
request to an acc queue and PDSP is not running. So make sure to copy firmware
|
||||
to file system before using these queue types.
|
@ -25,7 +25,7 @@ SunXi family
|
||||
+ Datasheet
|
||||
http://dl.linux-sunxi.org/A10s/A10s%20Datasheet%20-%20v1.20%20%282012-03-27%29.pdf
|
||||
|
||||
- Allwinner A13 (sun5i)
|
||||
- Allwinner A13 / R8 (sun5i)
|
||||
+ Datasheet
|
||||
http://dl.linux-sunxi.org/A13/A13%20Datasheet%20-%20v1.12%20%282012-03-29%29.pdf
|
||||
+ User Manual
|
||||
|
@ -27,6 +27,11 @@ Required properties:
|
||||
* For "marvell,armada-380-coherency-fabric", only one pair is needed
|
||||
for the per-CPU fabric registers.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- broken-idle: boolean to set when the Idle mode is not supported by the
|
||||
hardware.
|
||||
|
||||
Examples:
|
||||
|
||||
coherency-fabric@d0020200 {
|
||||
|
20
Documentation/devicetree/bindings/arm/mvebu-cpu-config.txt
Normal file
20
Documentation/devicetree/bindings/arm/mvebu-cpu-config.txt
Normal file
@ -0,0 +1,20 @@
|
||||
MVEBU CPU Config registers
|
||||
--------------------------
|
||||
|
||||
MVEBU (Marvell SOCs: Armada 370/XP)
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: one of:
|
||||
- "marvell,armada-370-cpu-config"
|
||||
- "marvell,armada-xp-cpu-config"
|
||||
|
||||
- reg: Should contain CPU config registers location and length, in
|
||||
their per-CPU variant
|
||||
|
||||
Example:
|
||||
|
||||
cpu-config@21000 {
|
||||
compatible = "marvell,armada-xp-cpu-config";
|
||||
reg = <0x21000 0x8>;
|
||||
};
|
@ -6,6 +6,7 @@ using one of the following compatible strings:
|
||||
allwinner,sun4i-a10
|
||||
allwinner,sun5i-a10s
|
||||
allwinner,sun5i-a13
|
||||
allwinner,sun5i-r8
|
||||
allwinner,sun6i-a31
|
||||
allwinner,sun7i-a20
|
||||
allwinner,sun8i-a23
|
||||
|
@ -0,0 +1,60 @@
|
||||
UniPhier outer cache controller
|
||||
|
||||
UniPhier SoCs are integrated with a full-custom outer cache controller system.
|
||||
All of them have a level 2 cache controller, and some have a level 3 cache
|
||||
controller as well.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "socionext,uniphier-system-cache"
|
||||
- reg: offsets and lengths of the register sets for the device. It should
|
||||
contain 3 regions: control register, revision register, operation register,
|
||||
in this order.
|
||||
- cache-unified: specifies the cache is a unified cache.
|
||||
- cache-size: specifies the size in bytes of the cache
|
||||
- cache-sets: specifies the number of associativity sets of the cache
|
||||
- cache-line-size: specifies the line size in bytes
|
||||
- cache-level: specifies the level in the cache hierarchy. The value should
|
||||
be 2 for L2 cache, 3 for L3 cache, etc.
|
||||
|
||||
Optional properties:
|
||||
- next-level-cache: phandle to the next level cache if present. The next level
|
||||
cache should be also compatible with "socionext,uniphier-system-cache".
|
||||
|
||||
The L2 cache must exist to use the L3 cache; the cache hierarchy must be
|
||||
indicated correctly with "next-level-cache" properties.
|
||||
|
||||
Example 1 (system with L2):
|
||||
l2: l2-cache@500c0000 {
|
||||
compatible = "socionext,uniphier-system-cache";
|
||||
reg = <0x500c0000 0x2000>, <0x503c0100 0x4>,
|
||||
<0x506c0000 0x400>;
|
||||
cache-unified;
|
||||
cache-size = <0x80000>;
|
||||
cache-sets = <256>;
|
||||
cache-line-size = <128>;
|
||||
cache-level = <2>;
|
||||
};
|
||||
|
||||
Example 2 (system with L2 and L3):
|
||||
l2: l2-cache@500c0000 {
|
||||
compatible = "socionext,uniphier-system-cache";
|
||||
reg = <0x500c0000 0x2000>, <0x503c0100 0x8>,
|
||||
<0x506c0000 0x400>;
|
||||
cache-unified;
|
||||
cache-size = <0x200000>;
|
||||
cache-sets = <512>;
|
||||
cache-line-size = <128>;
|
||||
cache-level = <2>;
|
||||
next-level-cache = <&l3>;
|
||||
};
|
||||
|
||||
l3: l3-cache@500c8000 {
|
||||
compatible = "socionext,uniphier-system-cache";
|
||||
reg = <0x500c8000 0x2000>, <0x503c8100 0x8>,
|
||||
<0x506c8000 0x400>;
|
||||
cache-unified;
|
||||
cache-size = <0x400000>;
|
||||
cache-sets = <512>;
|
||||
cache-line-size = <256>;
|
||||
cache-level = <3>;
|
||||
};
|
@ -221,7 +221,6 @@ qmss: qmss@2a40000 {
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
pdsp0@0x2a10000 {
|
||||
firmware = "keystone/qmss_pdsp_acc48_k2_le_1_0_0_8.fw";
|
||||
reg = <0x2a10000 0x1000>,
|
||||
<0x2a0f000 0x100>,
|
||||
<0x2a0c000 0x3c8>,
|
||||
|
@ -920,7 +920,7 @@ M: Tsahee Zidenberg <tsahee@annapurnalabs.com>
|
||||
S: Maintained
|
||||
F: arch/arm/mach-alpine/
|
||||
|
||||
ARM/ATMEL AT91RM9200 AND AT91SAM ARM ARCHITECTURES
|
||||
ARM/ATMEL AT91RM9200, AT91SAM9 AND SAMA5 SOC SUPPORT
|
||||
M: Nicolas Ferre <nicolas.ferre@atmel.com>
|
||||
M: Alexandre Belloni <alexandre.belloni@free-electrons.com>
|
||||
M: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>
|
||||
@ -1630,7 +1630,9 @@ M: Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: arch/arm/boot/dts/uniphier*
|
||||
F: arch/arm/include/asm/hardware/cache-uniphier.h
|
||||
F: arch/arm/mach-uniphier/
|
||||
F: arch/arm/mm/cache-uniphier.c
|
||||
F: drivers/i2c/busses/i2c-uniphier*
|
||||
F: drivers/pinctrl/uniphier/
|
||||
F: drivers/tty/serial/8250/8250_uniphier.c
|
||||
|
@ -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;
|
||||
}
|
@ -7,6 +7,7 @@ config ARCH_BCM_IPROC
|
||||
|
||||
config ARCH_BERLIN
|
||||
bool "Marvell Berlin SoC Family"
|
||||
select ARCH_REQUIRE_GPIOLIB
|
||||
select DW_APB_ICTL
|
||||
help
|
||||
This enables support for Marvell Berlin SoC Family
|
||||
|
@ -259,6 +259,10 @@ int cpg_mstp_attach_dev(struct generic_pm_domain *domain, struct device *dev)
|
||||
"renesas,cpg-mstp-clocks"))
|
||||
goto found;
|
||||
|
||||
/* BSC on r8a73a4/sh73a0 uses zb_clk instead of an mstp clock */
|
||||
if (!strcmp(clkspec.np->name, "zb_clk"))
|
||||
goto found;
|
||||
|
||||
of_node_put(clkspec.np);
|
||||
i++;
|
||||
}
|
||||
|
@ -1196,6 +1196,7 @@ static void __init sun5i_init_clocks(struct device_node *node)
|
||||
}
|
||||
CLK_OF_DECLARE(sun5i_a10s_clk_init, "allwinner,sun5i-a10s", sun5i_init_clocks);
|
||||
CLK_OF_DECLARE(sun5i_a13_clk_init, "allwinner,sun5i-a13", sun5i_init_clocks);
|
||||
CLK_OF_DECLARE(sun5i_r8_clk_init, "allwinner,sun5i-r8", sun5i_init_clocks);
|
||||
CLK_OF_DECLARE(sun7i_a20_clk_init, "allwinner,sun7i-a20", sun5i_init_clocks);
|
||||
|
||||
static const char *sun6i_critical_clocks[] __initdata = {
|
||||
|
@ -1,5 +1,6 @@
|
||||
menu "SOC (System On Chip) specific Drivers"
|
||||
|
||||
source "drivers/soc/brcmstb/Kconfig"
|
||||
source "drivers/soc/mediatek/Kconfig"
|
||||
source "drivers/soc/qcom/Kconfig"
|
||||
source "drivers/soc/sunxi/Kconfig"
|
||||
|
@ -2,6 +2,7 @@
|
||||
# Makefile for the Linux Kernel SOC specific device drivers.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/
|
||||
obj-$(CONFIG_MACH_DOVE) += dove/
|
||||
obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
|
||||
obj-$(CONFIG_ARCH_QCOM) += qcom/
|
||||
|
9
drivers/soc/brcmstb/Kconfig
Normal file
9
drivers/soc/brcmstb/Kconfig
Normal file
@ -0,0 +1,9 @@
|
||||
menuconfig SOC_BRCMSTB
|
||||
bool "Broadcom STB SoC drivers"
|
||||
depends on ARM
|
||||
help
|
||||
Enables drivers for the Broadcom Set-Top Box (STB) series of chips.
|
||||
This option alone enables only some support code, while the drivers
|
||||
can be enabled individually within this menu.
|
||||
|
||||
If unsure, say N.
|
1
drivers/soc/brcmstb/Makefile
Normal file
1
drivers/soc/brcmstb/Makefile
Normal file
@ -0,0 +1 @@
|
||||
obj-y += common.o biuctrl.o
|
116
drivers/soc/brcmstb/biuctrl.c
Normal file
116
drivers/soc/brcmstb/biuctrl.c
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Broadcom STB SoCs Bus Unit Interface controls
|
||||
*
|
||||
* 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 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.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "brcmstb: " KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
#define CPU_CREDIT_REG_OFFSET 0x184
|
||||
#define CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK 0x70000000
|
||||
|
||||
static void __iomem *cpubiuctrl_base;
|
||||
static bool mcp_wr_pairing_en;
|
||||
|
||||
static int __init mcp_write_pairing_set(void)
|
||||
{
|
||||
u32 creds = 0;
|
||||
|
||||
if (!cpubiuctrl_base)
|
||||
return -1;
|
||||
|
||||
creds = readl_relaxed(cpubiuctrl_base + CPU_CREDIT_REG_OFFSET);
|
||||
if (mcp_wr_pairing_en) {
|
||||
pr_info("MCP: Enabling write pairing\n");
|
||||
writel_relaxed(creds | CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK,
|
||||
cpubiuctrl_base + CPU_CREDIT_REG_OFFSET);
|
||||
} else if (creds & CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK) {
|
||||
pr_info("MCP: Disabling write pairing\n");
|
||||
writel_relaxed(creds & ~CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK,
|
||||
cpubiuctrl_base + CPU_CREDIT_REG_OFFSET);
|
||||
} else {
|
||||
pr_info("MCP: Write pairing already disabled\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init setup_hifcpubiuctrl_regs(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
int ret = 0;
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "brcm,brcmstb-cpu-biu-ctrl");
|
||||
if (!np) {
|
||||
pr_err("missing BIU control node\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
cpubiuctrl_base = of_iomap(np, 0);
|
||||
if (!cpubiuctrl_base) {
|
||||
pr_err("failed to remap BIU control base\n");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mcp_wr_pairing_en = of_property_read_bool(np, "brcm,write-pairing");
|
||||
out:
|
||||
of_node_put(np);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static u32 cpu_credit_reg_dump; /* for save/restore */
|
||||
|
||||
static int brcmstb_cpu_credit_reg_suspend(void)
|
||||
{
|
||||
if (cpubiuctrl_base)
|
||||
cpu_credit_reg_dump =
|
||||
readl_relaxed(cpubiuctrl_base + CPU_CREDIT_REG_OFFSET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void brcmstb_cpu_credit_reg_resume(void)
|
||||
{
|
||||
if (cpubiuctrl_base)
|
||||
writel_relaxed(cpu_credit_reg_dump,
|
||||
cpubiuctrl_base + CPU_CREDIT_REG_OFFSET);
|
||||
}
|
||||
|
||||
static struct syscore_ops brcmstb_cpu_credit_syscore_ops = {
|
||||
.suspend = brcmstb_cpu_credit_reg_suspend,
|
||||
.resume = brcmstb_cpu_credit_reg_resume,
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
void __init brcmstb_biuctrl_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
setup_hifcpubiuctrl_regs();
|
||||
|
||||
ret = mcp_write_pairing_set();
|
||||
if (ret) {
|
||||
pr_err("MCP: Unable to disable write pairing!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
register_syscore_ops(&brcmstb_cpu_credit_syscore_ops);
|
||||
#endif
|
||||
}
|
33
drivers/soc/brcmstb/common.c
Normal file
33
drivers/soc/brcmstb/common.c
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright © 2014 NVIDIA Corporation
|
||||
* Copyright © 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 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/of.h>
|
||||
|
||||
#include <soc/brcmstb/common.h>
|
||||
|
||||
static const struct of_device_id brcmstb_machine_match[] = {
|
||||
{ .compatible = "brcm,brcmstb", },
|
||||
{ }
|
||||
};
|
||||
|
||||
bool soc_is_brcmstb(void)
|
||||
{
|
||||
struct device_node *root;
|
||||
|
||||
root = of_find_node_by_path("/");
|
||||
if (!root)
|
||||
return false;
|
||||
|
||||
return of_match_node(brcmstb_machine_match, root) != NULL;
|
||||
}
|
@ -725,10 +725,6 @@ static int pwrap_init(struct pmic_wrapper *wrp)
|
||||
pwrap_writel(wrp, 0x1, PWRAP_WACS2_EN);
|
||||
pwrap_writel(wrp, 0x5, PWRAP_STAUPD_PRD);
|
||||
pwrap_writel(wrp, 0xff, PWRAP_STAUPD_GRPEN);
|
||||
pwrap_writel(wrp, 0xf, PWRAP_WDT_UNIT);
|
||||
pwrap_writel(wrp, 0xffffffff, PWRAP_WDT_SRC_EN);
|
||||
pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN);
|
||||
pwrap_writel(wrp, ~((1 << 31) | (1 << 1)), PWRAP_INT_EN);
|
||||
|
||||
if (pwrap_is_mt8135(wrp)) {
|
||||
/* enable pwrap events and pwrap bridge in AP side */
|
||||
@ -896,6 +892,12 @@ static int pwrap_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Initialize watchdog, may not be done by the bootloader */
|
||||
pwrap_writel(wrp, 0xf, PWRAP_WDT_UNIT);
|
||||
pwrap_writel(wrp, 0xffffffff, PWRAP_WDT_SRC_EN);
|
||||
pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN);
|
||||
pwrap_writel(wrp, ~((1 << 31) | (1 << 1)), PWRAP_INT_EN);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
ret = devm_request_irq(wrp->dev, irq, pwrap_interrupt, IRQF_TRIGGER_HIGH,
|
||||
"mt-pmic-pwrap", wrp);
|
||||
|
@ -54,12 +54,16 @@
|
||||
#define PWR_STATUS_USB BIT(25)
|
||||
|
||||
enum clk_id {
|
||||
MT8173_CLK_NONE,
|
||||
MT8173_CLK_MM,
|
||||
MT8173_CLK_MFG,
|
||||
MT8173_CLK_NONE,
|
||||
MT8173_CLK_MAX = MT8173_CLK_NONE,
|
||||
MT8173_CLK_VENC,
|
||||
MT8173_CLK_VENC_LT,
|
||||
MT8173_CLK_MAX,
|
||||
};
|
||||
|
||||
#define MAX_CLKS 2
|
||||
|
||||
struct scp_domain_data {
|
||||
const char *name;
|
||||
u32 sta_mask;
|
||||
@ -67,7 +71,8 @@ struct scp_domain_data {
|
||||
u32 sram_pdn_bits;
|
||||
u32 sram_pdn_ack_bits;
|
||||
u32 bus_prot_mask;
|
||||
enum clk_id clk_id;
|
||||
enum clk_id clk_id[MAX_CLKS];
|
||||
bool active_wakeup;
|
||||
};
|
||||
|
||||
static const struct scp_domain_data scp_domain_data[] __initconst = {
|
||||
@ -77,7 +82,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = {
|
||||
.ctl_offs = SPM_VDE_PWR_CON,
|
||||
.sram_pdn_bits = GENMASK(11, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.clk_id = MT8173_CLK_MM,
|
||||
.clk_id = {MT8173_CLK_MM},
|
||||
},
|
||||
[MT8173_POWER_DOMAIN_VENC] = {
|
||||
.name = "venc",
|
||||
@ -85,7 +90,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = {
|
||||
.ctl_offs = SPM_VEN_PWR_CON,
|
||||
.sram_pdn_bits = GENMASK(11, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(15, 12),
|
||||
.clk_id = MT8173_CLK_MM,
|
||||
.clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC},
|
||||
},
|
||||
[MT8173_POWER_DOMAIN_ISP] = {
|
||||
.name = "isp",
|
||||
@ -93,7 +98,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = {
|
||||
.ctl_offs = SPM_ISP_PWR_CON,
|
||||
.sram_pdn_bits = GENMASK(11, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(13, 12),
|
||||
.clk_id = MT8173_CLK_MM,
|
||||
.clk_id = {MT8173_CLK_MM},
|
||||
},
|
||||
[MT8173_POWER_DOMAIN_MM] = {
|
||||
.name = "mm",
|
||||
@ -101,7 +106,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = {
|
||||
.ctl_offs = SPM_DIS_PWR_CON,
|
||||
.sram_pdn_bits = GENMASK(11, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.clk_id = MT8173_CLK_MM,
|
||||
.clk_id = {MT8173_CLK_MM},
|
||||
.bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
|
||||
MT8173_TOP_AXI_PROT_EN_MM_M1,
|
||||
},
|
||||
@ -111,7 +116,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = {
|
||||
.ctl_offs = SPM_VEN2_PWR_CON,
|
||||
.sram_pdn_bits = GENMASK(11, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(15, 12),
|
||||
.clk_id = MT8173_CLK_MM,
|
||||
.clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC_LT},
|
||||
},
|
||||
[MT8173_POWER_DOMAIN_AUDIO] = {
|
||||
.name = "audio",
|
||||
@ -119,7 +124,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = {
|
||||
.ctl_offs = SPM_AUDIO_PWR_CON,
|
||||
.sram_pdn_bits = GENMASK(11, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(15, 12),
|
||||
.clk_id = MT8173_CLK_NONE,
|
||||
.clk_id = {MT8173_CLK_NONE},
|
||||
},
|
||||
[MT8173_POWER_DOMAIN_USB] = {
|
||||
.name = "usb",
|
||||
@ -127,7 +132,8 @@ static const struct scp_domain_data scp_domain_data[] __initconst = {
|
||||
.ctl_offs = SPM_USB_PWR_CON,
|
||||
.sram_pdn_bits = GENMASK(11, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(15, 12),
|
||||
.clk_id = MT8173_CLK_NONE,
|
||||
.clk_id = {MT8173_CLK_NONE},
|
||||
.active_wakeup = true,
|
||||
},
|
||||
[MT8173_POWER_DOMAIN_MFG_ASYNC] = {
|
||||
.name = "mfg_async",
|
||||
@ -135,7 +141,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = {
|
||||
.ctl_offs = SPM_MFG_ASYNC_PWR_CON,
|
||||
.sram_pdn_bits = GENMASK(11, 8),
|
||||
.sram_pdn_ack_bits = 0,
|
||||
.clk_id = MT8173_CLK_MFG,
|
||||
.clk_id = {MT8173_CLK_MFG},
|
||||
},
|
||||
[MT8173_POWER_DOMAIN_MFG_2D] = {
|
||||
.name = "mfg_2d",
|
||||
@ -143,7 +149,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = {
|
||||
.ctl_offs = SPM_MFG_2D_PWR_CON,
|
||||
.sram_pdn_bits = GENMASK(11, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(13, 12),
|
||||
.clk_id = MT8173_CLK_NONE,
|
||||
.clk_id = {MT8173_CLK_NONE},
|
||||
},
|
||||
[MT8173_POWER_DOMAIN_MFG] = {
|
||||
.name = "mfg",
|
||||
@ -151,7 +157,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = {
|
||||
.ctl_offs = SPM_MFG_PWR_CON,
|
||||
.sram_pdn_bits = GENMASK(13, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(21, 16),
|
||||
.clk_id = MT8173_CLK_NONE,
|
||||
.clk_id = {MT8173_CLK_NONE},
|
||||
.bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
|
||||
MT8173_TOP_AXI_PROT_EN_MFG_M0 |
|
||||
MT8173_TOP_AXI_PROT_EN_MFG_M1 |
|
||||
@ -166,12 +172,13 @@ struct scp;
|
||||
struct scp_domain {
|
||||
struct generic_pm_domain genpd;
|
||||
struct scp *scp;
|
||||
struct clk *clk;
|
||||
struct clk *clk[MAX_CLKS];
|
||||
u32 sta_mask;
|
||||
void __iomem *ctl_addr;
|
||||
u32 sram_pdn_bits;
|
||||
u32 sram_pdn_ack_bits;
|
||||
u32 bus_prot_mask;
|
||||
bool active_wakeup;
|
||||
};
|
||||
|
||||
struct scp {
|
||||
@ -212,11 +219,16 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
|
||||
u32 sram_pdn_ack = scpd->sram_pdn_ack_bits;
|
||||
u32 val;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) {
|
||||
ret = clk_prepare_enable(scpd->clk[i]);
|
||||
if (ret) {
|
||||
for (--i; i >= 0; i--)
|
||||
clk_disable_unprepare(scpd->clk[i]);
|
||||
|
||||
if (scpd->clk) {
|
||||
ret = clk_prepare_enable(scpd->clk);
|
||||
if (ret)
|
||||
goto err_clk;
|
||||
}
|
||||
}
|
||||
|
||||
val = readl(ctl_addr);
|
||||
@ -282,7 +294,10 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
|
||||
return 0;
|
||||
|
||||
err_pwr_ack:
|
||||
clk_disable_unprepare(scpd->clk);
|
||||
for (i = MAX_CLKS - 1; i >= 0; i--) {
|
||||
if (scpd->clk[i])
|
||||
clk_disable_unprepare(scpd->clk[i]);
|
||||
}
|
||||
err_clk:
|
||||
dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name);
|
||||
|
||||
@ -299,6 +314,7 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
|
||||
u32 pdn_ack = scpd->sram_pdn_ack_bits;
|
||||
u32 val;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (scpd->bus_prot_mask) {
|
||||
ret = mtk_infracfg_set_bus_protection(scp->infracfg,
|
||||
@ -360,8 +376,8 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
|
||||
expired = true;
|
||||
}
|
||||
|
||||
if (scpd->clk)
|
||||
clk_disable_unprepare(scpd->clk);
|
||||
for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++)
|
||||
clk_disable_unprepare(scpd->clk[i]);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -371,11 +387,22 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool scpsys_active_wakeup(struct device *dev)
|
||||
{
|
||||
struct generic_pm_domain *genpd;
|
||||
struct scp_domain *scpd;
|
||||
|
||||
genpd = pd_to_genpd(dev->pm_domain);
|
||||
scpd = container_of(genpd, struct scp_domain, genpd);
|
||||
|
||||
return scpd->active_wakeup;
|
||||
}
|
||||
|
||||
static int __init scpsys_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct genpd_onecell_data *pd_data;
|
||||
struct resource *res;
|
||||
int i, ret;
|
||||
int i, j, ret;
|
||||
struct scp *scp;
|
||||
struct clk *clk[MT8173_CLK_MAX];
|
||||
|
||||
@ -405,6 +432,14 @@ static int __init scpsys_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(clk[MT8173_CLK_MFG]))
|
||||
return PTR_ERR(clk[MT8173_CLK_MFG]);
|
||||
|
||||
clk[MT8173_CLK_VENC] = devm_clk_get(&pdev->dev, "venc");
|
||||
if (IS_ERR(clk[MT8173_CLK_VENC]))
|
||||
return PTR_ERR(clk[MT8173_CLK_VENC]);
|
||||
|
||||
clk[MT8173_CLK_VENC_LT] = devm_clk_get(&pdev->dev, "venc_lt");
|
||||
if (IS_ERR(clk[MT8173_CLK_VENC_LT]))
|
||||
return PTR_ERR(clk[MT8173_CLK_VENC_LT]);
|
||||
|
||||
scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
|
||||
"infracfg");
|
||||
if (IS_ERR(scp->infracfg)) {
|
||||
@ -428,12 +463,14 @@ static int __init scpsys_probe(struct platform_device *pdev)
|
||||
scpd->sram_pdn_bits = data->sram_pdn_bits;
|
||||
scpd->sram_pdn_ack_bits = data->sram_pdn_ack_bits;
|
||||
scpd->bus_prot_mask = data->bus_prot_mask;
|
||||
if (data->clk_id != MT8173_CLK_NONE)
|
||||
scpd->clk = clk[data->clk_id];
|
||||
scpd->active_wakeup = data->active_wakeup;
|
||||
for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++)
|
||||
scpd->clk[j] = clk[data->clk_id[j]];
|
||||
|
||||
genpd->name = data->name;
|
||||
genpd->power_off = scpsys_power_off;
|
||||
genpd->power_on = scpsys_power_on;
|
||||
genpd->dev_ops.active_wakeup = scpsys_active_wakeup;
|
||||
|
||||
/*
|
||||
* Initially turn on all domains to make the domains usable
|
||||
|
@ -135,9 +135,10 @@ struct knav_pdsp_info {
|
||||
};
|
||||
void __iomem *intd;
|
||||
u32 __iomem *iram;
|
||||
const char *firmware;
|
||||
u32 id;
|
||||
struct list_head list;
|
||||
bool loaded;
|
||||
bool started;
|
||||
};
|
||||
|
||||
struct knav_qmgr_info {
|
||||
|
@ -486,8 +486,8 @@ struct knav_range_ops knav_acc_range_ops = {
|
||||
* Return 0 on success or error
|
||||
*/
|
||||
int knav_init_acc_range(struct knav_device *kdev,
|
||||
struct device_node *node,
|
||||
struct knav_range_info *range)
|
||||
struct device_node *node,
|
||||
struct knav_range_info *range)
|
||||
{
|
||||
struct knav_acc_channel *acc;
|
||||
struct knav_pdsp_info *pdsp;
|
||||
@ -530,6 +530,12 @@ int knav_init_acc_range(struct knav_device *kdev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pdsp->started) {
|
||||
dev_err(kdev->dev, "pdsp id %d not started for range %s\n",
|
||||
info->pdsp_id, range->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
info->pdsp = pdsp;
|
||||
channels = range->num_queues;
|
||||
if (of_get_property(node, "multi-queue", NULL)) {
|
||||
|
@ -68,6 +68,12 @@ static DEFINE_MUTEX(knav_dev_lock);
|
||||
idx < (kdev)->num_queues_in_use; \
|
||||
idx++, inst = knav_queue_idx_to_inst(kdev, idx))
|
||||
|
||||
/* All firmware file names end up here. List the firmware file names below.
|
||||
* Newest followed by older ones. Search is done from start of the array
|
||||
* until a firmware file is found.
|
||||
*/
|
||||
const char *knav_acc_firmwares[] = {"ks2_qmss_pdsp_acc48.bin"};
|
||||
|
||||
/**
|
||||
* knav_queue_notify: qmss queue notfier call
|
||||
*
|
||||
@ -1439,7 +1445,6 @@ static int knav_queue_init_pdsps(struct knav_device *kdev,
|
||||
struct device *dev = kdev->dev;
|
||||
struct knav_pdsp_info *pdsp;
|
||||
struct device_node *child;
|
||||
int ret;
|
||||
|
||||
for_each_child_of_node(pdsps, child) {
|
||||
pdsp = devm_kzalloc(dev, sizeof(*pdsp), GFP_KERNEL);
|
||||
@ -1448,17 +1453,6 @@ static int knav_queue_init_pdsps(struct knav_device *kdev,
|
||||
return -ENOMEM;
|
||||
}
|
||||
pdsp->name = knav_queue_find_name(child);
|
||||
ret = of_property_read_string(child, "firmware",
|
||||
&pdsp->firmware);
|
||||
if (ret < 0 || !pdsp->firmware) {
|
||||
dev_err(dev, "unknown firmware for pdsp %s\n",
|
||||
pdsp->name);
|
||||
devm_kfree(dev, pdsp);
|
||||
continue;
|
||||
}
|
||||
dev_dbg(dev, "pdsp name %s fw name :%s\n", pdsp->name,
|
||||
pdsp->firmware);
|
||||
|
||||
pdsp->iram =
|
||||
knav_queue_map_reg(kdev, child,
|
||||
KNAV_QUEUE_PDSP_IRAM_REG_INDEX);
|
||||
@ -1489,9 +1483,9 @@ static int knav_queue_init_pdsps(struct knav_device *kdev,
|
||||
}
|
||||
of_property_read_u32(child, "id", &pdsp->id);
|
||||
list_add_tail(&pdsp->list, &kdev->pdsps);
|
||||
dev_dbg(dev, "added pdsp %s: command %p, iram %p, regs %p, intd %p, firmware %s\n",
|
||||
dev_dbg(dev, "added pdsp %s: command %p, iram %p, regs %p, intd %p\n",
|
||||
pdsp->name, pdsp->command, pdsp->iram, pdsp->regs,
|
||||
pdsp->intd, pdsp->firmware);
|
||||
pdsp->intd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -1510,6 +1504,8 @@ static int knav_queue_stop_pdsp(struct knav_device *kdev,
|
||||
dev_err(kdev->dev, "timed out on pdsp %s stop\n", pdsp->name);
|
||||
return ret;
|
||||
}
|
||||
pdsp->loaded = false;
|
||||
pdsp->started = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1518,14 +1514,29 @@ static int knav_queue_load_pdsp(struct knav_device *kdev,
|
||||
{
|
||||
int i, ret, fwlen;
|
||||
const struct firmware *fw;
|
||||
bool found = false;
|
||||
u32 *fwdata;
|
||||
|
||||
ret = request_firmware(&fw, pdsp->firmware, kdev->dev);
|
||||
if (ret) {
|
||||
dev_err(kdev->dev, "failed to get firmware %s for pdsp %s\n",
|
||||
pdsp->firmware, pdsp->name);
|
||||
return ret;
|
||||
for (i = 0; i < ARRAY_SIZE(knav_acc_firmwares); i++) {
|
||||
if (knav_acc_firmwares[i]) {
|
||||
ret = request_firmware(&fw,
|
||||
knav_acc_firmwares[i],
|
||||
kdev->dev);
|
||||
if (!ret) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
dev_err(kdev->dev, "failed to get firmware for pdsp\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev_info(kdev->dev, "firmware file %s downloaded for PDSP\n",
|
||||
knav_acc_firmwares[i]);
|
||||
|
||||
writel_relaxed(pdsp->id + 1, pdsp->command + 0x18);
|
||||
/* download the firmware */
|
||||
fwdata = (u32 *)fw->data;
|
||||
@ -1583,16 +1594,24 @@ static int knav_queue_start_pdsps(struct knav_device *kdev)
|
||||
int ret;
|
||||
|
||||
knav_queue_stop_pdsps(kdev);
|
||||
/* now load them all */
|
||||
/* now load them all. We return success even if pdsp
|
||||
* is not loaded as acc channels are optional on having
|
||||
* firmware availability in the system. We set the loaded
|
||||
* and stated flag and when initialize the acc range, check
|
||||
* it and init the range only if pdsp is started.
|
||||
*/
|
||||
for_each_pdsp(kdev, pdsp) {
|
||||
ret = knav_queue_load_pdsp(kdev, pdsp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (!ret)
|
||||
pdsp->loaded = true;
|
||||
}
|
||||
|
||||
for_each_pdsp(kdev, pdsp) {
|
||||
ret = knav_queue_start_pdsp(kdev, pdsp);
|
||||
WARN_ON(ret);
|
||||
if (pdsp->loaded) {
|
||||
ret = knav_queue_start_pdsp(kdev, pdsp);
|
||||
if (!ret)
|
||||
pdsp->started = true;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
47
include/linux/mfd/syscon/imx7-iomuxc-gpr.h
Normal file
47
include/linux/mfd/syscon/imx7-iomuxc-gpr.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_IMX7_IOMUXC_GPR_H
|
||||
#define __LINUX_IMX7_IOMUXC_GPR_H
|
||||
|
||||
#define IOMUXC_GPR0 0x00
|
||||
#define IOMUXC_GPR1 0x04
|
||||
#define IOMUXC_GPR2 0x08
|
||||
#define IOMUXC_GPR3 0x0c
|
||||
#define IOMUXC_GPR4 0x10
|
||||
#define IOMUXC_GPR5 0x14
|
||||
#define IOMUXC_GPR6 0x18
|
||||
#define IOMUXC_GPR7 0x1c
|
||||
#define IOMUXC_GPR8 0x20
|
||||
#define IOMUXC_GPR9 0x24
|
||||
#define IOMUXC_GPR10 0x28
|
||||
#define IOMUXC_GPR11 0x2c
|
||||
#define IOMUXC_GPR12 0x30
|
||||
#define IOMUXC_GPR13 0x34
|
||||
#define IOMUXC_GPR14 0x38
|
||||
#define IOMUXC_GPR15 0x3c
|
||||
#define IOMUXC_GPR16 0x40
|
||||
#define IOMUXC_GPR17 0x44
|
||||
#define IOMUXC_GPR18 0x48
|
||||
#define IOMUXC_GPR19 0x4c
|
||||
#define IOMUXC_GPR20 0x50
|
||||
#define IOMUXC_GPR21 0x54
|
||||
#define IOMUXC_GPR22 0x58
|
||||
|
||||
/* For imx7d iomux gpr register field define */
|
||||
#define IMX7D_GPR1_IRQ_MASK (0x1 << 12)
|
||||
#define IMX7D_GPR1_ENET1_TX_CLK_SEL_MASK (0x1 << 13)
|
||||
#define IMX7D_GPR1_ENET2_TX_CLK_SEL_MASK (0x1 << 14)
|
||||
#define IMX7D_GPR1_ENET_TX_CLK_SEL_MASK (0x3 << 13)
|
||||
#define IMX7D_GPR1_ENET1_CLK_DIR_MASK (0x1 << 17)
|
||||
#define IMX7D_GPR1_ENET2_CLK_DIR_MASK (0x1 << 18)
|
||||
#define IMX7D_GPR1_ENET_CLK_DIR_MASK (0x3 << 17)
|
||||
|
||||
#define IMX7D_GPR5_CSI_MUX_CONTROL_MIPI (0x1 << 4)
|
||||
|
||||
#endif /* __LINUX_IMX7_IOMUXC_GPR_H */
|
@ -9,15 +9,7 @@
|
||||
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/usb/atmel_usba_udc.h>
|
||||
#include <linux/atmel-mci.h>
|
||||
#include <sound/atmel-ac97c.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/platform_data/macb.h>
|
||||
|
||||
/* Compact Flash */
|
||||
struct at91_cf_data {
|
||||
|
10
include/linux/soc/brcmstb/brcmstb.h
Normal file
10
include/linux/soc/brcmstb/brcmstb.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef __BRCMSTB_SOC_H
|
||||
#define __BRCMSTB_SOC_H
|
||||
|
||||
/*
|
||||
* Bus Interface Unit control register setup, must happen early during boot,
|
||||
* before SMP is brought up, called by machine entry point.
|
||||
*/
|
||||
void brcmstb_biuctrl_init(void);
|
||||
|
||||
#endif /* __BRCMSTB_SOC_H */
|
15
include/soc/brcmstb/common.h
Normal file
15
include/soc/brcmstb/common.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright © 2014 NVIDIA Corporation
|
||||
* Copyright © 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 version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __SOC_BRCMSTB_COMMON_H__
|
||||
#define __SOC_BRCMSTB_COMMON_H__
|
||||
|
||||
bool soc_is_brcmstb(void);
|
||||
|
||||
#endif /* __SOC_BRCMSTB_COMMON_H__ */
|
Loading…
Reference in New Issue
Block a user